From 01a2cd566690f070f3f59770fd8c034af3d6c4f0 Mon Sep 17 00:00:00 2001 From: sjvenditto Date: Mon, 23 Sep 2024 15:15:05 -0400 Subject: [PATCH 001/107] make files for sphinx --- docs/Makefile | 20 ++++++++++++++++++++ docs/conf.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ docs/index.md | 30 ++++++++++++++++++++++++++++-- docs/index.rst | 18 ++++++++++++++++++ docs/make.bat | 35 +++++++++++++++++++++++++++++++++++ 5 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 docs/Makefile create mode 100644 docs/conf.py create mode 100644 docs/index.rst create mode 100644 docs/make.bat diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..d4bb2cbb --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..a968cdc7 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,45 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = 'nemos' +copyright = '2024, SJ Venditto' +author = 'SJ Venditto' +release = '0' + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = ['myst_parser', + 'sphinx_design'] + +myst_enable_extensions = [ + "amsmath", + "attrs_inline", + "colon_fence", + "deflist", + "dollarmath", + "fieldlist", + "html_admonition", + "html_image", + "replacements", + "smartquotes", + "strikethrough", + "substitution", + "tasklist", +] + +templates_path = ['_templates'] +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + + + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = 'sphinx_book_theme' +html_static_path = ['_static'] diff --git a/docs/index.md b/docs/index.md index d09b0f60..9f503ea0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,7 +6,7 @@ hide: #
-
+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/flatironinstitute/nemos/blob/main/LICENSE) ![Python version](https://img.shields.io/badge/python-3.10%7C3.11%7C3.12-blue.svg) [![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active) @@ -23,6 +23,13 @@ __Useful Links:__ [:material-chat-question: Getting Help](getting_help.md) | [:m +```{card} Card title +:header: The _Header_ +:footer: Footer + +Card content +``` + ## __Overview__ NeMoS (Neural ModelS) is a statistical modeling framework optimized for systems neuroscience and powered by [JAX](https://jax.readthedocs.io/en/latest/). @@ -33,8 +40,26 @@ focusing on the Generalized Linear Model (GLM). We provide a **Poisson GLM** for analyzing spike counts, and a **Gamma GLM** for calcium or voltage imaging traces. -
+::::{grid} 1 1 2 3 + +:::{card} +:header: Text content ✏️ +Structure books with text files and Jupyter Notebooks with minimal configuration. +::: + +:::{card} +:header: MyST Markdown ✨ +Write MyST Markdown to create enriched documents with publication-quality features. +::: + +:::{card} +:header: Executable content 🔁 +Execute notebook cells, store results, and insert outputs across pages. +::: +:::: + +
- :material-clock-fast:{ .lg .middle }   __Getting Started__ --- @@ -100,6 +125,7 @@ We provide a **Poisson GLM** for analyzing spike counts, and a **Gamma GLM** for
+ ## :material-scale-balance:{ .lg } License Open source, [licensed under MIT](https://github.com/flatironinstitute/nemos/blob/main/LICENSE). diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 00000000..01f646db --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,18 @@ +.. nemos documentation master file, created by + sphinx-quickstart on Mon Sep 23 12:12:31 2024. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +nemos documentation +=================== + +Add your content using ``reStructuredText`` syntax. See the +`reStructuredText `_ +documentation for details. + + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + Install diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 00000000..32bb2452 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd From 6350c2050da8b792637d26f63f2f46afd62e9f3e Mon Sep 17 00:00:00 2001 From: sjvenditto Date: Mon, 23 Sep 2024 15:50:01 -0400 Subject: [PATCH 002/107] empty space needed after div to interpret markdown within block --- docs/conf.py | 20 +++++++++++--------- docs/index.md | 8 ++++++-- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index a968cdc7..743ccc36 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -15,22 +15,24 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration extensions = ['myst_parser', - 'sphinx_design'] + 'sphinx_design', + # 'myst_nb', + ] myst_enable_extensions = [ "amsmath", "attrs_inline", "colon_fence", - "deflist", + # "deflist", "dollarmath", - "fieldlist", + # "fieldlist", "html_admonition", "html_image", - "replacements", - "smartquotes", - "strikethrough", - "substitution", - "tasklist", + # "replacements", + # "smartquotes", + # "strikethrough", + # "substitution", + # "tasklist", ] templates_path = ['_templates'] @@ -41,5 +43,5 @@ # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output -html_theme = 'sphinx_book_theme' +html_theme = 'sphinx_material' html_static_path = ['_static'] diff --git a/docs/index.md b/docs/index.md index 9f503ea0..ce3d1eaa 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,7 +6,9 @@ hide: #
-
+ +
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/flatironinstitute/nemos/blob/main/LICENSE) ![Python version](https://img.shields.io/badge/python-3.10%7C3.11%7C3.12-blue.svg) [![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active) @@ -15,11 +17,12 @@ hide: [![Documentation Status](https://readthedocs.org/projects/nemos/badge/?version=latest)](https://nemos.readthedocs.io/en/latest/?badge=latest) [![nemos CI](https://github.com/flatironinstitute/nemos/actions/workflows/ci.yml/badge.svg)](https://github.com/flatironinstitute/nemos/actions/workflows/ci.yml) +
+ __Learning Resources:__ [:material-book-open-variant-outline: Neuromatch Academy's Lessons](https://compneuro.neuromatch.io/tutorials/W1D3_GeneralizedLinearModels/student/W1D3_Tutorial1.html) | [:material-youtube: Cosyne 2018 Tutorial](https://www.youtube.com/watch?v=NFeGW5ljUoI&t=424s)
__Useful Links:__ [:material-chat-question: Getting Help](getting_help.md) | [:material-alert-circle-outline: Issue Tracker](https://github.com/flatironinstitute/nemos/issues) | [:material-order-bool-ascending-variant: Contributing Guidelines](https://github.com/flatironinstitute/nemos/blob/main/CONTRIBUTING.md) -
@@ -60,6 +63,7 @@ Execute notebook cells, store results, and insert outputs across pages. ::::
+ - :material-clock-fast:{ .lg .middle }   __Getting Started__ --- From dc0b273ef233c9c4ac07ad6f95c1443108f023a3 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 8 Nov 2024 10:38:07 -0500 Subject: [PATCH 003/107] start editing landing page --- docs/assets/extra.css | 3 - docs/assets/stylesheets/custom.css | 21 +++ docs/conf.py | 91 +++++++++++- docs/gallery_conf.py | 23 --- docs/gen_ref_pages.py | 60 -------- docs/index.md | 216 +++++++++++++++++++++-------- mkdocs.yml | 98 ------------- pyproject.toml | 21 +-- 8 files changed, 280 insertions(+), 253 deletions(-) delete mode 100644 docs/assets/extra.css create mode 100644 docs/assets/stylesheets/custom.css delete mode 100644 docs/gallery_conf.py delete mode 100644 docs/gen_ref_pages.py delete mode 100644 mkdocs.yml diff --git a/docs/assets/extra.css b/docs/assets/extra.css deleted file mode 100644 index 288364bd..00000000 --- a/docs/assets/extra.css +++ /dev/null @@ -1,3 +0,0 @@ -.notes { - display: none; -} diff --git a/docs/assets/stylesheets/custom.css b/docs/assets/stylesheets/custom.css new file mode 100644 index 00000000..6b5d41e0 --- /dev/null +++ b/docs/assets/stylesheets/custom.css @@ -0,0 +1,21 @@ + +.bd-main .bd-content .bd-article-container{ + max-width:100%; + flex-grow: 1; +} + +html[data-theme=light]{ + --pst-color-primary: rgb(52, 54, 99); + --pst-color-secondary: rgb(107, 161, 174); + --pst-color-link: rgb(74, 105, 145); + --pst-color-inline-code: rgb(96, 141, 130); +} + +:root { + --pst-font-size-h1: 38px; + --pst-font-size-h2: 32px; + --pst-font-size-h3: 27px; + --pst-font-size-h4: 22px; + --pst-font-size-h5: 18px; + --pst-font-size-h6: 15px; +} \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 743ccc36..e2d722ba 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -6,18 +6,36 @@ # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information +import nemos +import sys, os + +sys.path.insert(0, os.path.abspath('..')) +sys.path.insert(0, os.path.abspath('sphinxext')) + + project = 'nemos' copyright = '2024, SJ Venditto' author = 'SJ Venditto' -release = '0' +version = release = nemos.__version__ # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration -extensions = ['myst_parser', - 'sphinx_design', - # 'myst_nb', - ] +# The Root document +root_doc = "index" + +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.napoleon', + 'sphinx.ext.autosummary', + 'sphinx.ext.coverage', + 'sphinx.ext.viewcode', # Links to source code + 'sphinx.ext.doctest', + 'sphinx_copybutton', # Adds copy button to code blocks + 'sphinx_design', # For layout components + 'myst_nb', + 'sphinx_contributors' +] myst_enable_extensions = [ "amsmath", @@ -36,7 +54,7 @@ ] templates_path = ['_templates'] -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ['_build', 'Thumbs.db', 'nextgen', '.DS_Store'] @@ -45,3 +63,64 @@ html_theme = 'sphinx_material' html_static_path = ['_static'] + +# Generate the API documentation when building +autosummary_generate = True +numpydoc_show_class_members = True +autodoc_default_options = { + 'members': True, + 'inherited-members': True, + 'show-inheritance': True, + } + + +html_theme = 'pydata_sphinx_theme' + +html_logo = "assets/NeMoS_Logo_CMYK_Full.svg" +html_favicon = "assets/NeMoS_favicon.ico" + +# Additional theme options +html_theme_options = { + "icon_links": [ + { + "name": "GitHub", + "url": "https://github.com/flatironinstitute/nemos/", + "icon": "fab fa-github", + "type": "fontawesome", + }, + { + "name": "X", + "url": "https://x.com/nemos_neuro", + "icon": "fab fa-square-x-twitter", + "type": "fontawesome", + }, + ], + "show_prev_next": True, + "header_links_before_dropdown": 5, +} + +html_context = { + "default_mode": "light", +} + +# Path for static files (custom stylesheets or JavaScript) +html_static_path = ['assets/stylesheets'] +html_css_files = ['custom.css'] + +# Copybutton settings (to hide prompt) +copybutton_prompt_text = r">>> |\$ |# " +copybutton_prompt_is_regexp = True + +# Enable markdown and notebook support +myst_enable_extensions = ["colon_fence"] # For improved markdown + +# # ---------------------------------------------------------------------------- +# # -- Autodoc and Napoleon Options ------------------------------------------------- +autodoc_default_options = { + 'members': True, + 'undoc-members': True, + 'show-inheritance': True, +} +napoleon_numpy_docstring = True + +nitpicky = True diff --git a/docs/gallery_conf.py b/docs/gallery_conf.py deleted file mode 100644 index ca01af54..00000000 --- a/docs/gallery_conf.py +++ /dev/null @@ -1,23 +0,0 @@ -import os -import re -import sys - -from mkdocs_gallery.sorting import FileNameSortKey - -min_reported_time = 0 -if "SOURCE_DATE_EPOCH" in os.environ: - min_reported_time = sys.maxint if sys.version_info[0] == 2 else sys.maxsize - -# To be used as the "base" config, -# mkdocs-gallery is a port of sphinx-gallery. For a detailed list -# of configuration options see https://sphinx-gallery.github.io/stable/configuration.html -conf = { - # report runtime if larger than this value - "min_reported_time": min_reported_time, - # order your section in file name alphabetical order - "within_subsection_order": FileNameSortKey, - # run every script that matches pattern - # (here we match every file that ends in .py) - "filename_pattern": re.escape(os.sep) + r"plot_.+\.py$", - "ignore_pattern": r"(_plot_.+\.py$|_helpers\.py$)", -} diff --git a/docs/gen_ref_pages.py b/docs/gen_ref_pages.py deleted file mode 100644 index 36c53da5..00000000 --- a/docs/gen_ref_pages.py +++ /dev/null @@ -1,60 +0,0 @@ -"""Generate the code reference pages and navigation. - -See [CCN template repo](https://ccn-template.readthedocs.io/en/latest/notes/03-documentation/) for why. -""" - -from pathlib import Path - -import mkdocs_gen_files - -nav = mkdocs_gen_files.Nav() - -for path in sorted(Path("src").rglob("*.py")): - module_path = path.relative_to("src").with_suffix("") - doc_path = path.relative_to("src").with_suffix(".md") - full_doc_path = Path("reference", doc_path) - - parts = tuple(module_path.parts) - - if parts[-1] == "__init__": - parts = parts[:-1] - doc_path = doc_path.with_name("index.md") - full_doc_path = full_doc_path.with_name("index.md") - elif parts[-1] == "__main__": - continue - - # if the submodule is private, skip - if len(parts) > 1 and parts[1].startswith("_"): - continue - - nav[parts] = doc_path.as_posix() - # if the md file name is `module.md`, generate documentation from docstrings - if full_doc_path.name != 'index.md': - with mkdocs_gen_files.open(full_doc_path, "w") as fd: - ident = ".".join(parts) - fd.write(f"::: {ident}") - # if the md file name is `index.md`, add the list of modules with hyperlinks - else: - this_module_path = Path("src") / path.parent.name - module_index = "" - for module_scripts in sorted(this_module_path.rglob("*.py")): - if "__init__" in module_scripts.name: - continue - elif any(p.startswith("_") for p in module_scripts.parts): - continue - - module_index += f"* [{module_scripts.name.replace('.py', '')}]" \ - f"({module_scripts.name.replace('.py', '.md')})\n" - if any(p.startswith("_") for p in full_doc_path.parts) or full_doc_path.parts[-2] == "styles": - continue - print(full_doc_path) - with mkdocs_gen_files.open(full_doc_path, "w") as fd: - fd.write(module_index) - - - - - mkdocs_gen_files.set_edit_path(full_doc_path, path) - -with mkdocs_gen_files.open("reference/SUMMARY.md", "w") as nav_file: - nav_file.writelines(nav.build_literate_nav()) \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index ce3d1eaa..b38d1aa8 100644 --- a/docs/index.md +++ b/docs/index.md @@ -44,90 +44,196 @@ focusing on the Generalized Linear Model (GLM). We provide a **Poisson GLM** for analyzing spike counts, and a **Gamma GLM** for calcium or voltage imaging traces. -::::{grid} 1 1 2 3 +"""{grid} 2 +:gutter: 2 +:class-container: cards -:::{card} -:header: Text content ✏️ -Structure books with text files and Jupyter Notebooks with minimal configuration. -::: +"""{card} +:material-clock-fast: lg middle +__Getting Started__ -:::{card} -:header: MyST Markdown ✨ -Write MyST Markdown to create enriched documents with publication-quality features. -::: +--- -:::{card} -:header: Executable content 🔁 -Execute notebook cells, store results, and insert outputs across pages. -::: -:::: +New to NeMoS? Get the ball rolling with our quickstart. -
+[:octicons-arrow-right-24: Quickstart](quickstart.md) +""" + +"""{card} +:material-book-open-variant-outline: lg middle +__Background__ -- :material-clock-fast:{ .lg .middle }   __Getting Started__ +--- - --- +Refresh your theoretical knowledge before diving into data analysis with our notes. - New to NeMoS? Get the ball rolling with our quickstart. +[:octicons-arrow-right-24: Background](generated/background) +""" - [:octicons-arrow-right-24: Quickstart](quickstart.md) +"""{card} +:material-lightbulb-on-10: lg middle +__How-To Guide__ -- :material-book-open-variant-outline:{ .lg .middle }   __Background__ +--- - --- +Already familiar with the concepts? Learn how you to process and analyze your data with NeMoS. - Refresh your theoretical knowledge before diving into data analysis with our notes. +*Requires familiarity with the theory.* +[:octicons-arrow-right-24: How-To Guide](generated/how_to_guide) +""" - [:octicons-arrow-right-24: Background](generated/background) +"""{card} +:material-brain: lg middle +__Neural Modeling__ -- :material-lightbulb-on-10:{ .lg .middle }   __How-To Guide__ +--- - --- +Explore fully worked examples to learn how to analyze neural recordings from scratch. - Already familiar with the concepts? Learn how you to process and analyze your data with NeMoS. +*Requires familiarity with the theory.* +[:octicons-arrow-right-24: Tutorials](generated/tutorials) +""" - *Requires familiarity with the theory.*
- [:octicons-arrow-right-24: How-To Guide](generated/how_to_guide) +"""{card} +:material-cog: lg middle +__API Guide__ -- :material-brain:{ .lg .middle}   __Neural Modeling__ +--- - --- +Access a detailed description of each module and function, including parameters and functionality. - Explore fully worked examples to learn how to analyze neural recordings from scratch. +*Requires familiarity with the theory.* +[:octicons-arrow-right-24: API Guide](reference/SUMMARY.md) +""" - *Requires familiarity with the theory.*
- [:octicons-arrow-right-24: Tutorials](generated/tutorials) +"""{card} +:material-hammer-wrench: lg middle +__Installation Instructions__ -- :material-cog:{ .lg .middle }   __API Guide__ +--- - --- +Run the following `pip` command in your virtual environment. - Access a detailed description of each module and function, including parameters and functionality. +=== "macOS/Linux" + + ```bash + pip install nemos + ``` - *Requires familiarity with the theory.*
- [:octicons-arrow-right-24: API Guide](reference/SUMMARY.md) +=== "Windows" + + ```bash + python -m pip install nemos + ``` -- :material-hammer-wrench:{ .lg .middle }   __Installation Instructions__ +*For more information see:* +[:octicons-arrow-right-24: Install](installation.md) +""" +``` - --- - - Run the following `pip` command in your virtual environment. - === "macOS/Linux" +**[//]: # (
) - ```bash - pip install nemos - ``` +[//]: # () +[//]: # (- :material-clock-fast:{ .lg .middle }   __Getting Started__) - === "Windows" - - ``` - python -m pip install nemos - ``` - - *For more information see:*
- [:octicons-arrow-right-24: Install](installation.md) +[//]: # () +[//]: # ( ---) -
+[//]: # () +[//]: # ( New to NeMoS? Get the ball rolling with our quickstart.) + +[//]: # () +[//]: # ( [:octicons-arrow-right-24: Quickstart](quickstart.md)) + +[//]: # () +[//]: # (- :material-book-open-variant-outline:{ .lg .middle }   __Background__) + +[//]: # () +[//]: # ( ---) + +[//]: # () +[//]: # ( Refresh your theoretical knowledge before diving into data analysis with our notes.) + +[//]: # () +[//]: # ( [:octicons-arrow-right-24: Background](generated/background)) + +[//]: # () +[//]: # (- :material-lightbulb-on-10:{ .lg .middle }   __How-To Guide__) + +[//]: # () +[//]: # ( ---) + +[//]: # () +[//]: # ( Already familiar with the concepts? Learn how you to process and analyze your data with NeMoS.) + +[//]: # () +[//]: # ( *Requires familiarity with the theory.*
) + +[//]: # ( [:octicons-arrow-right-24: How-To Guide](generated/how_to_guide)) + +[//]: # () +[//]: # (- :material-brain:{ .lg .middle}   __Neural Modeling__) + +[//]: # () +[//]: # ( ---) + +[//]: # () +[//]: # ( Explore fully worked examples to learn how to analyze neural recordings from scratch.) + +[//]: # () +[//]: # ( *Requires familiarity with the theory.*
) + +[//]: # ( [:octicons-arrow-right-24: Tutorials](generated/tutorials)) + +[//]: # () +[//]: # (- :material-cog:{ .lg .middle }   __API Guide__) + +[//]: # () +[//]: # ( ---) + +[//]: # () +[//]: # ( Access a detailed description of each module and function, including parameters and functionality. ) + +[//]: # () +[//]: # ( *Requires familiarity with the theory.*
) + +[//]: # ( [:octicons-arrow-right-24: API Guide](reference/SUMMARY.md)) + +[//]: # () +[//]: # (- :material-hammer-wrench:{ .lg .middle }   __Installation Instructions__ ) + +[//]: # () +[//]: # ( ---) + +[//]: # ( ) +[//]: # ( Run the following `pip` command in your virtual environment.) + +[//]: # ( === "macOS/Linux") + +[//]: # () +[//]: # ( ```bash) + +[//]: # ( pip install nemos) + +[//]: # ( ```) + +[//]: # () +[//]: # ( === "Windows") + +[//]: # ( ) +[//]: # ( ```) + +[//]: # ( python -m pip install nemos) + +[//]: # ( ```) + +[//]: # ( ) +[//]: # ( *For more information see:*
) + +[//]: # ( [:octicons-arrow-right-24: Install](installation.md)) + +[//]: # () +[//]: # (
)** ## :material-scale-balance:{ .lg } License diff --git a/mkdocs.yml b/mkdocs.yml deleted file mode 100644 index b53bea99..00000000 --- a/mkdocs.yml +++ /dev/null @@ -1,98 +0,0 @@ -site_name: NeMoS -repo_url: https://github.com/flatironinstitute/nemos - -theme: - name: 'material' # The theme name, using the 'material' theme - favicon: assets/NeMoS_favicon.ico - logo: assets/NeMoS_Icon_CMYK_White.svg - palette: - primary: 'light blue' # The primary color palette for the theme - features: - - navigation.tabs # Enable navigation tabs feature for the theme - markdown_extensions: - - attr_list - - admonition - - tables - - pymdownx.emoji: - emoji_index: !!python/name:material.extensions.emoji.twemoji - emoji_generator: !!python/name:material.extensions.emoji.to_svg - - features: - - content.tabs.link - - content.code.annotate - - content.code.copy - - announce.dismiss - - navigation.tabs - - navigation.instant - - navigation.instant.prefetch - - navigation.instant.preview - - navigation.instant.progress - - navigation.path - - navigation.sections - - navigation.top - - search.highlights - - search.share - - search.suggest - -markdown_extensions: - - md_in_html - - footnotes - - pymdownx.superfences - - pymdownx.details # add notes toggleable notes ??? - - pymdownx.tabbed: - alternate_style: true - - toc: - title: On this page - - -plugins: - - search - - gallery: - conf_script: docs/gallery_conf.py - # These directories contain the input .py scripts for mkdocs-gallery - examples_dirs: - - docs/background - - docs/how_to_guide - - docs/tutorials - # These are the output directories for mkdocs-gallery, and correspond - # directly to the input dirs listed above. their contents should not be - # touched - gallery_dirs: - - docs/generated/background - - docs/generated/how_to_guide - - docs/generated/tutorials - - gen-files: - scripts: - - docs/gen_ref_pages.py # Specify the script to generate the code reference pages - - literate-nav: - nav_file: docs/SUMMARY.md # Specify the navigation file for literate-style navigation - - section-index # Enable the section-index plugin for generating a section index - - mkdocstrings: - handlers: - python: - options: - docstring_style: numpy - show_source: true - members_order: source - inherited_members: true - -extra_javascript: - - javascripts/katex.js - - javascripts/toggle_code.js - - https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.7/katex.min.js - - https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.7/contrib/auto-render.min.js - -extra_css: - - https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.7/katex.min.css - - assets/stylesheets/extra.css - -nav: - - Home: index.md # Link to the index.md file (home page) - - Install: installation.md # Link to the installation.md file - - Quickstart: quickstart.md - - Background: generated/background # Link to the generated gallery Tutorials - - How-To Guide: generated/how_to_guide # Link to the generated gallery tutorials - - Tutorials: generated/tutorials # Link to the generated gallery tutorials - - Getting Help: getting_help.md - - API Guide: reference/ # Link to the reference/ directory - - For Developers: developers_notes/ # Link to the developers notes diff --git a/pyproject.toml b/pyproject.toml index 672fd095..c5bfd300 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,14 +52,19 @@ dev = [ "scikit-learn", # Testing compatibility with CV & pipelines ] docs = [ - "mkdocs", # Documentation generator - "mkdocstrings[python]", # Python-specific plugin for mkdocs - "mkdocs-section-index", # Plugin for generating a section index in mkdocs - "mkdocs-gen-files", # Plugin for generating additional files in mkdocs - "mkdocs-literate-nav>=0.6.1", # Plugin for literate-style navigation in mkdocs - "mkdocs-gallery", # Plugin for adding image galleries to mkdocs - "mkdocs-material", # Material theme for mkdocs - "mkdocs-autorefs>=0.5", + "numpydoc", + "sphinx", + "pydata-sphinx-theme", + "sphinx-autodoc-typehints", + "sphinx-copybutton", + "sphinx-design", + "sphinx-issues", + "sphinxcontrib-apidoc", + "myst-parser", + "myst-nb", + "dandi", + "sphinx-autobuild", + "sphinx-contributors", "scikit-learn", "dandi", "ipython", From 6607cfa85fe46815ca263cf782c5bc47db1605db Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Mon, 11 Nov 2024 18:31:59 -0500 Subject: [PATCH 004/107] started changing docs --- docs/CCN-logo-wText.png | Bin 57441 -> 0 bytes docs/api_guide.rst | 17 ++ docs/assets/CCN-logo-wText.png | Bin 0 -> 52002 bytes docs/assets/stylesheets/custom.css | 57 +++++++ docs/assets/stylesheets/extra.css | 33 ---- docs/conf.py | 63 +++++--- docs/getting_help.md | 7 +- docs/index.md | 247 +++++++++-------------------- docs/index.rst | 18 --- docs/installation.md | 5 +- src/nemos/glm.py | 107 +++++++++---- 11 files changed, 268 insertions(+), 286 deletions(-) delete mode 100644 docs/CCN-logo-wText.png create mode 100644 docs/api_guide.rst create mode 100644 docs/assets/CCN-logo-wText.png delete mode 100644 docs/assets/stylesheets/extra.css delete mode 100644 docs/index.rst diff --git a/docs/CCN-logo-wText.png b/docs/CCN-logo-wText.png deleted file mode 100644 index 51fc110dfb81cdd197fef223692c48ff95f2a93c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 57441 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

0|nu@a0s0uZ4Puh?~5E;cVt!!}DI|J^xTM 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 RB?kr|@O1TaS?83{1ON#1?j!&J diff --git a/docs/api_guide.rst b/docs/api_guide.rst new file mode 100644 index 00000000..93d24caf --- /dev/null +++ b/docs/api_guide.rst @@ -0,0 +1,17 @@ +.. _api_ref: + +API Guide +--------- + +.. rubric:: The GLM module + + +.. currentmodule:: nemos.glm + +.. autosummary:: + :toctree: stubs + :recursive: + :nosignatures: + + GLM + PopulationGLM diff --git a/docs/assets/CCN-logo-wText.png b/docs/assets/CCN-logo-wText.png new file mode 100644 index 0000000000000000000000000000000000000000..206f7693b63d5e9e542aeaff535b83a79ea74b91 GIT binary patch literal 52002 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

Z(Ve*0{JkzD2>Ju$gX?S}eu_&2; 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 literal 0 HcmV?d00001 diff --git a/docs/assets/stylesheets/custom.css b/docs/assets/stylesheets/custom.css index 6b5d41e0..13d88188 100644 --- a/docs/assets/stylesheets/custom.css +++ b/docs/assets/stylesheets/custom.css @@ -18,4 +18,61 @@ html[data-theme=light]{ --pst-font-size-h4: 22px; --pst-font-size-h5: 18px; --pst-font-size-h6: 15px; +} + +.iconify { + display: inline-block; + width: 2em; + height: 2em; + vertical-align: middle; +} + +.cards { + display: grid; + gap: 2rem; /* Adjust as needed */ +} + +@media (min-width: 1024px) { + .cards { + grid-template-columns: repeat(3, 1fr); /* 3 columns on large screens */ + } +} + +@media (min-width: 768px) and (max-width: 1023px) { + .cards { + grid-template-columns: repeat(2, 1fr); /* 2 columns on medium screens */ + } +} + +@media (max-width: 767px) { + .cards { + grid-template-columns: 1fr; /* 1 column on small screens */ + } +} + +.sd-card-title { + height: 2.5rem; /* Adjust to a height that fits your content */ + display: flex; + align-items: center; + margin-bottom: 0.5rem; /* Spacing between title and separator */ +} + + +.sd-card-body hr { + width: 100%; + border: 0; + border-top: 2px solid #ddd; /* Light gray for a subtle line */ + margin: 5%; /* Remove any default margin around the


*/ +} + +.sd-card-body { + padding-top: .5rem; /* Adjust padding for consistent layout */ +} + +.card-footer-content { + margin-top: auto; /* Pushes the footer content to the bottom */ +} + +.sphinxsidebar .globaltoc { + display: none; } \ No newline at end of file diff --git a/docs/assets/stylesheets/extra.css b/docs/assets/stylesheets/extra.css deleted file mode 100644 index c9150f33..00000000 --- a/docs/assets/stylesheets/extra.css +++ /dev/null @@ -1,33 +0,0 @@ -/* Flexbox layout for the list items */ -.grid.cards ul > li { - display: flex !important; /* Ensure flexbox is applied */ - flex-direction: column; - justify-content: space-between; - height: 100%; - box-sizing: border-box; -} - -/* Ensure the link stays at the bottom */ -.grid.cards ul > li > p:last-of-type { - margin-top: auto; - padding-top: 10px; /* Optional spacing */ -} - -/* Adjust the spacing for the hr element */ -.grid.cards ul > li > hr { - margin: 10px 0; /* Adjust this value to match the original spacing */ - flex-shrink: 0; /* Prevent the hr from shrinking */ -} - -/* Center the icon and title within the first paragraph */ -.grid.cards ul > li > p:first-of-type { - display: flex; - align-items: center; - justify-content: center; - text-align: center; -} - -/* Add spacing between the icon and the title */ -.grid.cards ul > li > p:first-of-type img { - margin-right: 8px; -} diff --git a/docs/conf.py b/docs/conf.py index e2d722ba..abea523c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -8,8 +8,9 @@ import nemos import sys, os +from pathlib import Path -sys.path.insert(0, os.path.abspath('..')) +sys.path.insert(0, str(Path('..', 'src').resolve())) sys.path.insert(0, os.path.abspath('sphinxext')) @@ -27,14 +28,16 @@ extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.napoleon', - 'sphinx.ext.autosummary', + 'numpydoc', 'sphinx.ext.coverage', 'sphinx.ext.viewcode', # Links to source code 'sphinx.ext.doctest', 'sphinx_copybutton', # Adds copy button to code blocks 'sphinx_design', # For layout components 'myst_nb', - 'sphinx_contributors' + 'sphinx_contributors', + 'sphinx_code_tabs', + 'sphinx.ext.mathjax', ] myst_enable_extensions = [ @@ -54,25 +57,42 @@ ] templates_path = ['_templates'] -exclude_patterns = ['_build', 'Thumbs.db', 'nextgen', '.DS_Store'] +exclude_patterns = ['_build', "docstrings", 'Thumbs.db', 'nextgen', '.DS_Store'] # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output -html_theme = 'sphinx_material' -html_static_path = ['_static'] # Generate the API documentation when building autosummary_generate = True numpydoc_show_class_members = True autodoc_default_options = { 'members': True, - 'inherited-members': True, + 'undoc-members': True, 'show-inheritance': True, - } +} + +# napolean configs +napoleon_google_docstring = False +napoleon_numpy_docstring = True +napoleon_include_init_with_doc = False +napoleon_include_private_with_doc = False +napoleon_include_special_with_doc = True +napoleon_use_admonition_for_examples = False +napoleon_use_admonition_for_notes = False +napoleon_use_admonition_for_references = False +napoleon_use_ivar = False +napoleon_use_param = True +napoleon_use_rtype = True + +autodoc_typehints = "description" # Use "description" to place hints in the description, or "signature" for inline hints +autodoc_type_aliases = { + "ArrayLike": "ArrayLike", +} +numfig = True html_theme = 'pydata_sphinx_theme' @@ -103,24 +123,29 @@ "default_mode": "light", } + +html_sidebars = { + "index": [], + "installation":[], + "quickstart": [], + "background/README": [], + "how_to_guide/README": [], + "tutorials/README": [], + "**": ["search-field.html", "sidebar-nav-bs.html"], +} + + # Path for static files (custom stylesheets or JavaScript) html_static_path = ['assets/stylesheets'] html_css_files = ['custom.css'] +html_js_files = [ + "https://code.iconify.design/2/2.2.1/iconify.min.js" +] + # Copybutton settings (to hide prompt) copybutton_prompt_text = r">>> |\$ |# " copybutton_prompt_is_regexp = True -# Enable markdown and notebook support -myst_enable_extensions = ["colon_fence"] # For improved markdown - -# # ---------------------------------------------------------------------------- -# # -- Autodoc and Napoleon Options ------------------------------------------------- -autodoc_default_options = { - 'members': True, - 'undoc-members': True, - 'show-inheritance': True, -} -napoleon_numpy_docstring = True nitpicky = True diff --git a/docs/getting_help.md b/docs/getting_help.md index 9381a49c..eb6fc896 100644 --- a/docs/getting_help.md +++ b/docs/getting_help.md @@ -1,8 +1,5 @@ ---- -hide: - - navigation - - toc ---- + +# Getting Help We communicate via several channels on Github: diff --git a/docs/index.md b/docs/index.md index b38d1aa8..23f15fb3 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,39 +1,25 @@ ---- -hide: - - navigation - - toc ---- - -#
- - -
- -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/flatironinstitute/nemos/blob/main/LICENSE) -![Python version](https://img.shields.io/badge/python-3.10%7C3.11%7C3.12-blue.svg) -[![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active) -![PyPI - Version](https://img.shields.io/pypi/v/nemos) -[![codecov](https://codecov.io/gh/flatironinstitute/nemos/graph/badge.svg?token=vvtrcTFNeu)](https://codecov.io/gh/flatironinstitute/nemos) -[![Documentation Status](https://readthedocs.org/projects/nemos/badge/?version=latest)](https://nemos.readthedocs.io/en/latest/?badge=latest) -[![nemos CI](https://github.com/flatironinstitute/nemos/actions/workflows/ci.yml/badge.svg)](https://github.com/flatironinstitute/nemos/actions/workflows/ci.yml) - -
+(id:_home)= +```{eval-rst} +:html_theme.sidebar_secondary.remove: +``` -__Learning Resources:__ [:material-book-open-variant-outline: Neuromatch Academy's Lessons](https://compneuro.neuromatch.io/tutorials/W1D3_GeneralizedLinearModels/student/W1D3_Tutorial1.html) | [:material-youtube: Cosyne 2018 Tutorial](https://www.youtube.com/watch?v=NFeGW5ljUoI&t=424s)
-__Useful Links:__ [:material-chat-question: Getting Help](getting_help.md) | [:material-alert-circle-outline: Issue Tracker](https://github.com/flatironinstitute/nemos/issues) | [:material-order-bool-ascending-variant: Contributing Guidelines](https://github.com/flatironinstitute/nemos/blob/main/CONTRIBUTING.md) - - - - -```{card} Card title -:header: The _Header_ -:footer: Footer - -Card content +```{toctree} +:maxdepth: 1 +:hidden: + +Install +Quickstart +Background +How-To Guide +Tutorials +Getting Help +API Guide +For Developers ``` -## __Overview__ + +## __Neural ModelS__ NeMoS (Neural ModelS) is a statistical modeling framework optimized for systems neuroscience and powered by [JAX](https://jax.readthedocs.io/en/latest/). It streamlines the process of defining and selecting models, through a collection of easy-to-use methods for feature design. @@ -44,198 +30,111 @@ focusing on the Generalized Linear Model (GLM). We provide a **Poisson GLM** for analyzing spike counts, and a **Gamma GLM** for calcium or voltage imaging traces. -"""{grid} 2 -:gutter: 2 -:class-container: cards -"""{card} -:material-clock-fast: lg middle -__Getting Started__ ---- - -New to NeMoS? Get the ball rolling with our quickstart. - -[:octicons-arrow-right-24: Quickstart](quickstart.md) -""" - -"""{card} -:material-book-open-variant-outline: lg middle -__Background__ +::::{grid} 1 2 3 3 +:::{grid-item-card}   **Installation Instructions** +:link: installation.html +:link-alt: Install --- -Refresh your theoretical knowledge before diving into data analysis with our notes. - -[:octicons-arrow-right-24: Background](generated/background) -""" +Run the following `pip` command in your virtual environment. -"""{card} -:material-lightbulb-on-10: lg middle -__How-To Guide__ +```{code-block} ---- +pip install nemos -Already familiar with the concepts? Learn how you to process and analyze your data with NeMoS. +``` -*Requires familiarity with the theory.* -[:octicons-arrow-right-24: How-To Guide](generated/how_to_guide) -""" +::: -"""{card} -:material-brain: lg middle -__Neural Modeling__ +:::{grid-item-card}   **Getting Started** +:link: quickstart.html +:link-alt: Quickstart --- -Explore fully worked examples to learn how to analyze neural recordings from scratch. +New to NeMoS? Get the ball rolling with our quickstart. -*Requires familiarity with the theory.* -[:octicons-arrow-right-24: Tutorials](generated/tutorials) -""" +::: -"""{card} -:material-cog: lg middle -__API Guide__ +:::{grid-item-card}   **Background** +:link: background/README.html +:link-alt: Background --- -Access a detailed description of each module and function, including parameters and functionality. +Refresh your theoretical knowledge before diving into data analysis with our notes. -*Requires familiarity with the theory.* -[:octicons-arrow-right-24: API Guide](reference/SUMMARY.md) -""" +::: -"""{card} -:material-hammer-wrench: lg middle -__Installation Instructions__ +:::{grid-item-card}   **How-to Guide** +:link: how_to_guide/README.html +:link-alt: How-to-Guide --- -Run the following `pip` command in your virtual environment. - -=== "macOS/Linux" - - ```bash - pip install nemos - ``` - -=== "Windows" - - ```bash - python -m pip install nemos - ``` - -*For more information see:* -[:octicons-arrow-right-24: Install](installation.md) -""" -``` - -**[//]: # (
) - -[//]: # () -[//]: # (- :material-clock-fast:{ .lg .middle }   __Getting Started__) - -[//]: # () -[//]: # ( ---) - -[//]: # () -[//]: # ( New to NeMoS? Get the ball rolling with our quickstart.) - -[//]: # () -[//]: # ( [:octicons-arrow-right-24: Quickstart](quickstart.md)) - -[//]: # () -[//]: # (- :material-book-open-variant-outline:{ .lg .middle }   __Background__) - -[//]: # () -[//]: # ( ---) - -[//]: # () -[//]: # ( Refresh your theoretical knowledge before diving into data analysis with our notes.) - -[//]: # () -[//]: # ( [:octicons-arrow-right-24: Background](generated/background)) - -[//]: # () -[//]: # (- :material-lightbulb-on-10:{ .lg .middle }   __How-To Guide__) - -[//]: # () -[//]: # ( ---) +Already familiar with the concepts? Learn how you to process and analyze your data with NeMoS. -[//]: # () -[//]: # ( Already familiar with the concepts? Learn how you to process and analyze your data with NeMoS.) -[//]: # () -[//]: # ( *Requires familiarity with the theory.*
) + -[//]: # () -[//]: # ( ---) +::: -[//]: # () -[//]: # ( Explore fully worked examples to learn how to analyze neural recordings from scratch.) +:::{grid-item-card}   **Neural Modeling** +:link: tutorials/README.html +:link-alt: Tutorials -[//]: # () -[//]: # ( *Requires familiarity with the theory.*
) +--- -[//]: # ( [:octicons-arrow-right-24: Tutorials](generated/tutorials)) +Explore fully worked examples to learn how to analyze neural recordings from scratch. -[//]: # () -[//]: # (- :material-cog:{ .lg .middle }   __API Guide__) + -[//]: # () -[//]: # ( *Requires familiarity with the theory.*
) +::: -[//]: # ( [:octicons-arrow-right-24: API Guide](reference/SUMMARY.md)) +:::{grid-item-card}   **API Guide** +:link: api_guide.html +:link-alt: API Guide -[//]: # () -[//]: # (- :material-hammer-wrench:{ .lg .middle }   __Installation Instructions__ ) +--- -[//]: # () -[//]: # ( ---) +Access a detailed description of each module and function, including parameters and functionality. -[//]: # ( ) -[//]: # ( Run the following `pip` command in your virtual environment.) + -[//]: # ( pip install nemos) +::: -[//]: # ( ```) +:::: -[//]: # () -[//]: # ( === "Windows") -[//]: # ( ) -[//]: # ( ```) +
-[//]: # ( python -m pip install nemos) +__Learning Resources:__ [ Neuromatch Academy's Lessons](https://compneuro.neuromatch.io/tutorials/W1D3_GeneralizedLinearModels/student/W1D3_Tutorial1.html) | [ Cosyne 2018 Tutorial](https://www.youtube.com/watch?v=NFeGW5ljUoI&t=424s)
+__Useful Links:__ [ Getting Help](getting_help.md) | [ Issue Tracker](https://github.com/flatironinstitute/nemos/issues) | [ Contributing Guidelines](https://github.com/flatironinstitute/nemos/blob/main/CONTRIBUTING.md) -[//]: # ( ```) +
-[//]: # ( ) -[//]: # ( *For more information see:*
) -[//]: # ( [:octicons-arrow-right-24: Install](installation.md)) +## __License__ -[//]: # () -[//]: # (
)** +Open source, [licensed under MIT](https://github.com/flatironinstitute/nemos/blob/main/LICENSE). +## Support -## :material-scale-balance:{ .lg } License +This package is supported by the Center for Computational Neuroscience, in the Flatiron Institute of the Simons Foundation. -Open source, [licensed under MIT](https://github.com/flatironinstitute/nemos/blob/main/LICENSE). +Flatiron Center for Computational Neuroscience logo. diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index 01f646db..00000000 --- a/docs/index.rst +++ /dev/null @@ -1,18 +0,0 @@ -.. nemos documentation master file, created by - sphinx-quickstart on Mon Sep 23 12:12:31 2024. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -nemos documentation -=================== - -Add your content using ``reStructuredText`` syntax. See the -`reStructuredText `_ -documentation for details. - - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - Install diff --git a/docs/installation.md b/docs/installation.md index 80e2b3b5..49410ed6 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -1,7 +1,4 @@ ---- -hide: - - navigation ---- + ## Prerequisites diff --git a/src/nemos/glm.py b/src/nemos/glm.py index bec4304f..364a5714 100644 --- a/src/nemos/glm.py +++ b/src/nemos/glm.py @@ -53,12 +53,17 @@ class GLM(BaseRegressor): don't follow a normal distribution. Below is a table listing the default and available solvers for each regularizer. + +---------------+------------------+-------------------------------------------------------------+ | Regularizer | Default Solver | Available Solvers | - | ------------- | ---------------- | ----------------------------------------------------------- | + +===============+==================+=============================================================+ | UnRegularized | GradientDescent | GradientDescent, BFGS, LBFGS, NonlinearCG, ProximalGradient | + +---------------+------------------+-------------------------------------------------------------+ | Ridge | GradientDescent | GradientDescent, BFGS, LBFGS, NonlinearCG, ProximalGradient | + +---------------+------------------+-------------------------------------------------------------+ | Lasso | ProximalGradient | ProximalGradient | + +---------------+------------------+-------------------------------------------------------------+ | GroupLasso | ProximalGradient | ProximalGradient | + +---------------+------------------+-------------------------------------------------------------+ Parameters ---------- @@ -92,9 +97,9 @@ class GLM(BaseRegressor): solver_state_ : State of the solver after fitting. May include details like optimization error. scale_: - Scale parameter for the model. The scale parameter is the constant $\Phi$, for which - $\text{Var} \left( y \right) = \Phi V(\mu)$. This parameter, together with the estimate - of the mean $\mu$ fully specifies the distribution of the activity $y$. + Scale parameter for the model. The scale parameter is the constant :math:`\Phi`, for which + :math:`\text{Var} \left( y \right) = \Phi V(\mu)`. This parameter, together with the estimate + of the mean :math:`\mu` fully specifies the distribution of the activity :math:`y`. dof_resid_: Degrees of freedom for the residuals. @@ -214,7 +219,10 @@ def _check_input_and_params_consistency( Raises ------ ValueError + - If param and X have different structures. + + - if the number of features is inconsistent between params[1] and X (when provided). @@ -300,22 +308,32 @@ def predict(self, X: DESIGN_INPUT_TYPE) -> jnp.ndarray: Raises ------ NotFittedError - If ``fit`` has not been called first with this instance. + + - If ``fit`` has not been called first with this instance. ValueError + - If `params` is not a JAX pytree of size two. + + - If weights and bias terms in `params` don't have the expected dimensions. + + - If `X` is not three-dimensional. + + - If there's an inconsistent number of features between spike basis coefficients and `X`. See Also -------- - - [score](./#nemos.glm.GLM.score) + :meth:`nemos.glm.GLM.score` Score predicted rates against target spike counts. - - [simulate (feed-forward only)](../glm/#nemos.glm.GLM.simulate) - Simulate neural activity in response to a feed-forward input . - - [simulate_recurrent (feed-forward + coupling)](../simulation/#nemos.simulation.simulate_recurrent) + + :meth:`nemos.glm.GLM.simulate` + Simulate neural activity in response to a feed-forward input (feed-forward only). + + :meth:`nemos.simulation.simulate_recurrent` Simulate neural activity in response to a feed-forward input - using the GLM as a recurrent network. + using the GLM as a recurrent network (feed-forward + coupling). """ # check that the model is fitted self._check_is_fit() @@ -397,13 +415,15 @@ def score( Returns ------- score : - The log-likelihood or the pseudo-$R^2$ of the current model. + The log-likelihood or the pseudo-:math:`R^2` of the current model. Raises ------ NotFittedError + If ``fit`` has not been called first with this instance. ValueError + If X structure doesn't match the params, and if X and y have different number of samples. @@ -413,25 +433,25 @@ def score( among which the number of model parameters. The log-likelihood can assume both positive and negative values. - The Pseudo-$ R^2 $ is not equivalent to the $ R^2 $ value in linear regression. While both + The Pseudo-:math:`R^2` is not equivalent to the :math:`R^2` value in linear regression. While both provide a measure of model fit, and assume values in the [0,1] range, the methods and - interpretations can differ. The Pseudo-$ R^2 $ is particularly useful for generalized linear - models when the interpretation of the $ R^2 $ as explained variance does not apply + interpretations can differ. The Pseudo-:math:`R^2` is particularly useful for generalized linear + models when the interpretation of the :math:`R^2` as explained variance does not apply (i.e., when the observations are not Gaussian distributed). - Why does the traditional $R^2$ is usually a poor measure of performance in GLMs? + Why does the traditional :math:`R^2` is usually a poor measure of performance in GLMs? 1. In the context of GLMs the variance and the mean of the observations are related. Ignoring the relation between them can result in underestimating the model performance; for instance, when we model a Poisson variable with large mean we expect an equally large variance. In this scenario, even if our model perfectly captures the mean, - the high-variance will result in large residuals and low $R^2$. + the high-variance will result in large residuals and low :math:`R^2`. Additionally, when the mean of the observations varies, the variance will vary too. This - violates the "homoschedasticity" assumption, necessary for interpreting the $R^2$ as + violates the "homoschedasticity" assumption, necessary for interpreting the :math:`R^2` as variance explained. - 2. The $R^2$ capture the variance explained when the relationship between the observations and + 2. The :math:`R^2` capture the variance explained when the relationship between the observations and the predictors is linear. In GLMs, the link function sets a non-linear mapping between the predictors - and the mean of the observations, compromising the interpretation of the $R^2$. + and the mean of the observations, compromising the interpretation of the :math:`R^2`. Note that it is possible to re-normalized the residuals by a mean-dependent quantity proportional to the model standard deviation (i.e. Pearson residuals). This "rescaled" residual distribution however @@ -440,7 +460,7 @@ def score( for GLM modeling counting data. Refer to the `nmo.observation_models.Observations` concrete subclasses for the likelihood and - pseudo-$R^2$ equations. + pseudo-:math:`R^2` equations. """ self._check_is_fit() @@ -495,7 +515,7 @@ def _initialize_parameters( This method initializes the coefficients (spike basis coefficients) and intercepts (bias terms) required for the GLM. The coefficients are initialized to zeros with dimensions based on the input X. - If X is a FeaturePytree, the coefficients retain the pytree structure with arrays of zeros shaped + If X is a :class:`nemos.pytrees.FeaturePytree`, the coefficients retain the pytree structure with arrays of zeros shaped according to the features in X. If X is a simple ndarray, the coefficients are initialized as a 2D array. The intercepts are initialized based on the log mean of the target data y across the first axis, corresponding to the average log activity of the neuron. @@ -503,7 +523,7 @@ def _initialize_parameters( Parameters ---------- X : - The input data which can be a FeaturePytree with n_features arrays of shape (n_timebins, + The input data which can be a :class:`nemos.pytrees.FeaturePytree` with n_features arrays of shape (n_timebins, n_features), or a simple ndarray of shape (n_timebins, n_features). y : The target data array of shape (n_timebins, ), representing @@ -595,14 +615,27 @@ def fit( Raises ------ ValueError + - If `init_params` is not of length two. + + - If dimensionality of `init_params` are not correct. + + - If `X` is not two-dimensional. + + - If `y` is not one-dimensional. + + - If solver returns at least one NaN parameter, which means it found an invalid solution. Try tuning optimization hyperparameters. + TypeError + - If `init_params` are not array-like + + - If `init_params[i]` cannot be converted to jnp.ndarray for all i """ @@ -694,15 +727,15 @@ def simulate( Raises ------ NotFittedError - If the model hasn't been fitted prior to calling this method. + - If the model hasn't been fitted prior to calling this method. ValueError - If the instance has not been previously fitted. See Also -------- - [predict](./#nemos.glm.GLM.predict) : - Method to predict rates based on the model's parameters. + :meth:`nemos.glm.GLM.predict` + Method to predict rates based on the model's parameters. """ # check if the model is fit self._check_is_fit() @@ -923,7 +956,7 @@ def update( step sizes, and other optimizer-specific metrics. X : The predictors used in the model fitting process, which may include feature matrices - or FeaturePytree objects. + or :class:`nemos.pytrees.FeaturePytree` objects. y : The response variable or output data corresponding to the predictors, used in the model fitting process. @@ -992,15 +1025,20 @@ class PopulationGLM(GLM): combination of exogenous inputs (like convolved currents or light intensities) and a choice of observation model. It is suitable for scenarios where the relationship between predictors and the response variable might be non-linear, and the residuals don't follow a normal distribution. The predictors must be - stored in tabular format, shape (n_timebins, num_features) or as [FeaturePytree](../pytrees). + stored in tabular format, shape (n_timebins, num_features) or as :class:`nemos.pytrees.FeaturePytree`. Below is a table listing the default and available solvers for each regularizer. + +---------------+------------------+-------------------------------------------------------------+ | Regularizer | Default Solver | Available Solvers | - | ------------- | ---------------- | ----------------------------------------------------------- | + +===============+==================+=============================================================+ | UnRegularized | GradientDescent | GradientDescent, BFGS, LBFGS, NonlinearCG, ProximalGradient | + +---------------+------------------+-------------------------------------------------------------+ | Ridge | GradientDescent | GradientDescent, BFGS, LBFGS, NonlinearCG, ProximalGradient | + +---------------+------------------+-------------------------------------------------------------+ | Lasso | ProximalGradient | ProximalGradient | + +---------------+------------------+-------------------------------------------------------------+ | GroupLasso | ProximalGradient | ProximalGradient | + +---------------+------------------+-------------------------------------------------------------+ Parameters ---------- @@ -1024,7 +1062,7 @@ class PopulationGLM(GLM): E.g. stepsize, acceleration, value_and_grad, etc. See the jaxopt documentation for details on each solver's kwargs: https://jaxopt.github.io/stable/ feature_mask : - Either a matrix of shape (num_features, num_neurons) or a [FeaturePytree](../pytrees) of 0s and 1s, with + Either a matrix of shape (num_features, num_neurons) or a :meth:`nemos.pytrees.FeaturePytree` of 0s and 1s, with `feature_mask[feature_name]` of shape (num_neurons, ). The mask will be used to select which features are used as predictors for which neuron. @@ -1041,7 +1079,10 @@ class PopulationGLM(GLM): Raises ------ TypeError + - If provided `regularizer` or `observation_model` are not valid. + + - If provided `feature_mask` is not an array-like of dimension two. Examples @@ -1065,7 +1106,6 @@ class PopulationGLM(GLM): >>> # Check the fitted coefficients and intercepts >>> print("Model coefficients:") >>> print(model.coef_) - >>> # Example with a FeaturePytree mask >>> from nemos.pytrees import FeaturePytree >>> # Define two features @@ -1352,7 +1392,7 @@ def fit( - If `y` is not two-dimensional. - If the `feature_mask` is not of the right shape. - If solver returns at least one NaN parameter, which means it found - an invalid solution. Try tuning optimization hyperparameters. + an invalid solution. Try tuning optimization hyperparameters. TypeError - If `init_params` are not array-like - If `init_params[i]` cannot be converted to jnp.ndarray for all i @@ -1360,11 +1400,12 @@ def fit( Notes ----- The `feature_mask` is used to select features for each neuron, and it is - an NDArray or a `FeaturePytree` of 0s and 1s. In particular, + an NDArray or a :class:`nemos.pytrees.FeaturePytree` of 0s and 1s. In particular, - If the mask is in array format, feature `i` is a predictor for neuron `j` if `feature_mask[i, j] == 1`. - - If the mask is a `FeaturePytree`, then `"feature_name"` is a predictor of neuron `j` if + + - If the mask is a :class:`nemos.pytrees.FeaturePytree`, then `"feature_name"` is a predictor of neuron `j` if `feature_mask["feature_name"][j] == 1`. """ From df9bb7cee249b1552697f1573f3e38dc3f59d3c6 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Mon, 11 Nov 2024 19:20:06 -0500 Subject: [PATCH 005/107] added title --- docs/api_guide.rst | 2 +- docs/assets/stylesheets/custom.css | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/api_guide.rst b/docs/api_guide.rst index 93d24caf..8717f00f 100644 --- a/docs/api_guide.rst +++ b/docs/api_guide.rst @@ -3,7 +3,7 @@ API Guide --------- -.. rubric:: The GLM module +.. rubric:: The `nemos.glm` module .. currentmodule:: nemos.glm diff --git a/docs/assets/stylesheets/custom.css b/docs/assets/stylesheets/custom.css index 13d88188..75a1e54b 100644 --- a/docs/assets/stylesheets/custom.css +++ b/docs/assets/stylesheets/custom.css @@ -1,4 +1,3 @@ - .bd-main .bd-content .bd-article-container{ max-width:100%; flex-grow: 1; @@ -57,7 +56,6 @@ html[data-theme=light]{ margin-bottom: 0.5rem; /* Spacing between title and separator */ } - .sd-card-body hr { width: 100%; border: 0; @@ -75,4 +73,9 @@ html[data-theme=light]{ .sphinxsidebar .globaltoc { display: none; -} \ No newline at end of file +} + +/* Add vertical spacing between cards */ +.sd-col { + margin-bottom: 20px; /* Adjust this value as needed for desired spacing */ +} From 8b5a9405d54719278f4cf00e99f5a6af94f1b8dd Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Mon, 11 Nov 2024 19:35:55 -0500 Subject: [PATCH 006/107] improved ref --- docs/api_guide.rst | 21 ++++++++++++++++++++- src/nemos/basis.py | 10 ++++++---- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/docs/api_guide.rst b/docs/api_guide.rst index 8717f00f..024536cc 100644 --- a/docs/api_guide.rst +++ b/docs/api_guide.rst @@ -3,7 +3,7 @@ API Guide --------- -.. rubric:: The `nemos.glm` module +.. rubric:: The nemos.glm module .. currentmodule:: nemos.glm @@ -15,3 +15,22 @@ API Guide GLM PopulationGLM + +.. rubric:: The nemos.basis module + +.. currentmodule:: nemos.basis + +.. autosummary:: + :toctree: stubs + :recursive: + :nosignatures: + + BSplineBasis + CyclicBSplineBasis + MSplineBasis + OrthExponentialBasis + RaisedCosineLinearBasis + RaisedCosineLogBasis + AdditiveBasis + MultiplicativeBasis + TransformerBasis \ No newline at end of file diff --git a/src/nemos/basis.py b/src/nemos/basis.py index 2cc48f95..a020fc24 100644 --- a/src/nemos/basis.py +++ b/src/nemos/basis.py @@ -1514,7 +1514,9 @@ def evaluate_on_grid(self, n_samples: int) -> Tuple[NDArray, NDArray]: class BSplineBasis(SplineBasis): """ - B-spline[$^{[1]}$](#references) 1-dimensional basis functions. + B-spline 1-dimensional basis functions. + + Implementation of the one-dimensional BSpline basis [1]_. Parameters ---------- @@ -1543,9 +1545,9 @@ class BSplineBasis(SplineBasis): Spline order. - # References - ------------ - [1] Prautzsch, H., Boehm, W., Paluszny, M. (2002). B-spline representation. In: Bézier and B-Spline Techniques. + References + ---------- + .. [1] Prautzsch, H., Boehm, W., Paluszny, M. (2002). B-spline representation. In: Bézier and B-Spline Techniques. Mathematics and Visualization. Springer, Berlin, Heidelberg. https://doi.org/10.1007/978-3-662-04919-8_5 """ From ea1e13502fc200ccd8091b54b0b7fca3b4236cd2 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Tue, 12 Nov 2024 09:30:05 -0500 Subject: [PATCH 007/107] double ticks basis --- src/nemos/basis.py | 256 ++++++++++++++++++++++----------------------- 1 file changed, 128 insertions(+), 128 deletions(-) diff --git a/src/nemos/basis.py b/src/nemos/basis.py index 3ee6324b..5491fcbd 100644 --- a/src/nemos/basis.py +++ b/src/nemos/basis.py @@ -77,8 +77,8 @@ def min_max_rescale_samples( sample_pts: The original samples. bounds: - Sample bounds. `bounds[0]` and `bounds[1]` are mapped to 0 and 1, respectively. - Default are `min(sample_pts), max(sample_pts)`. + Sample bounds. ``bounds[0]`` and ``bounds[1]`` are mapped to 0 and 1, respectively. + Default are ``min(sample_pts), max(sample_pts)``. Warns ----- @@ -107,7 +107,7 @@ def min_max_rescale_samples( class TransformerBasis: - """Basis as `scikit-learn` transformers. + """Basis as ``scikit-learn`` transformers. This class abstracts the underlying basis function details, offering methods similar to scikit-learn's transformers but specifically designed for basis @@ -115,14 +115,14 @@ class TransformerBasis: of the basis functions), transforming data (applying the basis functions to data), and both fitting and transforming in one step. - `TransformerBasis`, unlike `Basis`, is compatible with scikit-learn pipelining and + ``TransformerBasis``, unlike ``Basis``, is compatible with scikit-learn pipelining and model selection, enabling the cross-validation of the basis type and parameters, - for example `n_basis_funcs`. See the example section below. + for example ``n_basis_funcs``. See the example section below. Parameters ---------- basis : - A concrete subclass of `Basis`. + A concrete subclass of ``Basis``. Examples -------- @@ -162,9 +162,9 @@ def __init__(self, basis: Basis): def _unpack_inputs(X: FeatureMatrix): """Unpack impute without using transpose. - Unpack horizontally stacked inputs using slicing. This works gracefully with `pynapple`, - returning a list of Tsd objects. Attempt to unpack using *X.T will raise a `pynapple` - exception since `pynapple` assumes that the time axis is the first axis. + Unpack horizontally stacked inputs using slicing. This works gracefully with ``pynapple``, + returning a list of Tsd objects. Attempt to unpack using *X.T will raise a ``pynapple`` + exception since ``pynapple`` assumes that the time axis is the first axis. Parameters ---------- @@ -343,7 +343,7 @@ def __setattr__(self, name: str, value) -> None: Raises ------ ValueError - If the attribute being set is not `_basis` or an attribute of `_basis`. + If the attribute being set is not ``_basis`` or an attribute of ``_basis``. Examples -------- @@ -389,7 +389,7 @@ def set_params(self, **parameters) -> TransformerBasis: """ Set TransformerBasis parameters. - When used with `sklearn.model_selection`, users can set either the `_basis` attribute directly + When used with ``sklearn.model_selection``, users can set either the ``_basis`` attribute directly or the parameters of the underlying Basis, but not both. Examples @@ -508,27 +508,27 @@ class Basis(Base, abc.ABC): window_size : The window size for convolution. Required if mode is 'conv'. bounds : - The bounds for the basis domain in `mode="eval"`. The default `bounds[0]` and `bounds[1]` are the + The bounds for the basis domain in ``mode="eval"``. The default ``bounds[0]`` and ``bounds[1]`` are the minimum and the maximum of the samples provided when evaluating the basis. If a sample is outside the bounds, the basis will return NaN. label : The label of the basis, intended to be descriptive of the task variable being processed. For example: velocity, position, spike_counts. **kwargs : - Additional keyword arguments passed to `nemos.convolve.create_convolutional_predictor` when - `mode='conv'`; These arguments are used to change the default behavior of the convolution. - For example, changing the `predictor_causality`, which by default is set to `"causal"`. - Note that one cannot change the default value for the `axis` parameter. Basis assumes - that the convolution axis is `axis=0`. + Additional keyword arguments passed to ``nemos.convolve.create_convolutional_predictor`` when + ``mode='conv'``; These arguments are used to change the default behavior of the convolution. + For example, changing the ``predictor_causality``, which by default is set to ``"causal"``. + Note that one cannot change the default value for the ``axis`` parameter. Basis assumes + that the convolution axis is ``axis=0``. Raises ------ ValueError: - - If `mode` is not 'eval' or 'conv'. - - If `kwargs` are not None and `mode =="eval". - - If `kwargs` include parameters not recognized or do not have - default values in `create_convolutional_predictor`. - - If `axis` different from 0 is provided as a keyword argument (samples must always be in the first axis). + - If ``mode`` is not 'eval' or 'conv'. + - If ``kwargs`` are not None and ``mode =="eval"``. + - If ``kwargs`` include parameters not recognized or do not have + default values in ``create_convolutional_predictor``. + - If ``axis`` different from 0 is provided as a keyword argument (samples must always be in the first axis). """ def __init__( @@ -548,7 +548,7 @@ def __init__( # check mode if mode not in ["conv", "eval"]: raise ValueError( - f"`mode` should be either 'conv' or 'eval'. '{mode}' provided instead!" + f"``mode`` should be either 'conv' or 'eval'. '{mode}' provided instead!" ) self._mode = mode @@ -578,11 +578,11 @@ def _check_convolution_kwargs(self): Raises ------ ValueError: - - If `self._conv_kwargs` are not None and `mode =="eval". - - If `axis` is provided as an argument, and it is different from 0 + - If ``self._conv_kwargs`` are not None and ``mode =="eval"``. + - If ``axis`` is provided as an argument, and it is different from 0 (samples must always be in the first axis). - - If `self._conv_kwargs` include parameters not recognized or that do not have - default values in `create_convolutional_predictor`. + - If ``self._conv_kwargs`` include parameters not recognized or that do not have + default values in ``create_convolutional_predictor``. """ if self._mode == "eval" and self._conv_kwargs: raise ValueError( @@ -627,8 +627,8 @@ def n_output_features(self) -> int | None: Notes ----- The number of output features can be determined only when the number of inputs - provided to the basis is known. Therefore, before the first call to `compute_features`, - this property will return `None`. After that call, `n_output_features` will be available. + provided to the basis is known. Therefore, before the first call to ``compute_features``, + this property will return ``None``. After that call, ``n_output_features`` will be available. """ return self._n_output_features @@ -714,9 +714,9 @@ def window_size(self, window_size): @staticmethod def _apply_identifiability_constraints(X: NDArray): - """Apply identifiability constraints to a design matrix `X`. + """Apply identifiability constraints to a design matrix ``X``. - Removes columns from `X` until `[1, X]` is full rank to ensure the uniqueness + Removes columns from ``X`` until ``[1, X]`` is full rank to ensure the uniqueness of the GLM (Generalized Linear Model) maximum-likelihood solution. This is particularly crucial for models using bases like BSplines and CyclicBspline, which, due to their construction, sum to 1 and can cause rank deficiency when combined with an intercept. @@ -768,16 +768,16 @@ def _compute_features(self, *xi: ArrayLike) -> FeatureMatrix: ------- : A matrix with the transformed features. The shape of the output depends on the operation mode: - - If `mode == 'eval'`, the basis evaluated at the samples, or $b_i(*xi)$, where $b_i$ is a + - If ``mode == 'eval'``, the basis evaluated at the samples, or $b_i(*xi)$, where $b_i$ is a basis element. xi[k] must be a one-dimensional array or a pynapple Tsd. - - If `mode == 'conv'`, a bank of basis filters (created by calling fit) is convolved with the + - If ``mode == 'conv'``, a bank of basis filters (created by calling fit) is convolved with the samples. Samples can be a NDArray, or a pynapple Tsd/TsdFrame/TsdTensor. All the dimensions except for the sample-axis are flattened, so that the method always returns a matrix. For example, if samples are of shape (num_samples, 2, 3), the output will be (num_samples, num_basis_funcs * 2 * 3). - The time-axis can be specified at basis initialization by setting the keyword argument `axis`. - For example, if `axis == 1` your samples should be (N1, num_samples N3, ...), the output of + The time-axis can be specified at basis initialization by setting the keyword argument ``axis``. + For example, if ``axis == 1`` your samples should be (N1, num_samples N3, ...), the output of transform will be (num_samples, num_basis_funcs * N1 * N3 *...). Raises @@ -878,7 +878,7 @@ def _set_kernel(self, *xi: ArrayLike) -> Basis: ----- Subclasses implementing this method should detail the specifics of how the kernel is computed and how the input parameters are utilized. If the basis operates in 'eval' - mode exclusively, this method should simply return `self` without modification. + mode exclusively, this method should simply return ``self`` without modification. """ if self.mode == "conv": self.kernel_ = self.__call__(np.linspace(0, 1, self.window_size)) @@ -924,7 +924,7 @@ def _get_samples(self, *n_samples: int) -> Generator[NDArray]: Returns ------- : - A generator yielding numpy arrays of linspaces from 0 to 1 of sizes specified by `n_samples`. + A generator yielding numpy arrays of linspaces from 0 to 1 of sizes specified by ``n_samples``. """ # handling of defaults when evaluating on a grid # (i.e. when we cannot use max and min of samples) @@ -977,14 +977,14 @@ def _check_has_kernel(self) -> None: """Check that the kernel is pre-computed.""" if self.mode == "conv" and self.kernel_ is None: raise ValueError( - "You must call `_set_kernel` before `_compute_features` when mode =`conv`." + "You must call ``_set_kernel`` before ``_compute_features`` when mode =``conv``." ) def evaluate_on_grid(self, *n_samples: int) -> Tuple[Tuple[NDArray], NDArray]: """Evaluate the basis set on a grid of equi-spaced sample points. The i-th axis of the grid will be sampled with n_samples[i] equi-spaced points. - The method uses numpy.meshgrid with `indexing="ij"`, returning matrix indexing + The method uses numpy.meshgrid with ``indexing="ij"``, returning matrix indexing instead of the default cartesian indexing, see Notes. Parameters @@ -1211,19 +1211,19 @@ def _get_feature_slicing( Calculate and return the slicing for features based on the input structure. This method determines how to slice the features for different basis types. - If the instance is of `AdditiveBasis` type, the slicing is calculated recursively + If the instance is of ``AdditiveBasis`` type, the slicing is calculated recursively for each component basis. Otherwise, it determines the slicing based on - the number of basis functions and `split_by_input` flag. + the number of basis functions and ``split_by_input`` flag. Parameters ---------- n_inputs : - The number of input basis for each component, by default it uses `self._n_basis_input`. + The number of input basis for each component, by default it uses ``self._n_basis_input``. start_slice : The starting index for slicing, by default it starts from 0. split_by_input : Flag indicating whether to split the slicing by individual inputs or not. - If `False`, a single slice is generated for all inputs. + If ``False``, a single slice is generated for all inputs. Returns ------- @@ -1326,45 +1326,45 @@ def split_by_feature( **How it works:** - - If the basis expects an input shape `(n_samples, n_inputs)`, then the feature axis length will - be `total_n_features = n_inputs * n_basis_funcs`. This axis is reshaped into dimensions - `(n_inputs, n_basis_funcs)`. - - If the basis expects an input of shape `(n_samples,)`, then the feature axis length will - be `total_n_features = n_basis_funcs`. This axis is reshaped into `(1, n_basis_funcs)`. + - If the basis expects an input shape ``(n_samples, n_inputs)``, then the feature axis length will + be ``total_n_features = n_inputs * n_basis_funcs``. This axis is reshaped into dimensions + ``(n_inputs, n_basis_funcs)``. + - If the basis expects an input of shape ``(n_samples,)``, then the feature axis length will + be ``total_n_features = n_basis_funcs``. This axis is reshaped into ``(1, n_basis_funcs)``. - For example, if the input array `x` has shape `(1, 2, total_n_features, 4, 5)`, - then after applying this method, it will be reshaped into `(1, 2, n_inputs, n_basis_funcs, 4, 5)`. + For example, if the input array ``x`` has shape ``(1, 2, total_n_features, 4, 5)``, + then after applying this method, it will be reshaped into ``(1, 2, n_inputs, n_basis_funcs, 4, 5)``. - The specified axis (`axis`) determines where the split occurs, and all other dimensions + The specified axis (``axis``) determines where the split occurs, and all other dimensions remain unchanged. See the example section below for the most common use cases. Parameters ---------- x : The input array to be split, representing concatenated features, coefficients, - or other data. The shape of `x` along the specified axis must match the total - number of features generated by the basis, i.e., `self.n_output_features`. + or other data. The shape of ``x`` along the specified axis must match the total + number of features generated by the basis, i.e., ``self.n_output_features``. **Examples:** - - For a design matrix: `(n_samples, total_n_features)` - - For model coefficients: `(total_n_features,)` or `(total_n_features, n_neurons)`. + - For a design matrix: ``(n_samples, total_n_features)`` + - For model coefficients: ``(total_n_features,)`` or ``(total_n_features, n_neurons)``. axis : int, optional The axis along which to split the features. Defaults to 1. - Use `axis=1` for design matrices (features along columns) and `axis=0` for + Use ``axis=1`` for design matrices (features along columns) and ``axis=0`` for coefficient arrays (features along rows). All other dimensions are preserved. Raises ------ ValueError - If the shape of `x` along the specified axis does not match `self.n_output_features`. + If the shape of ``x`` along the specified axis does not match ``self.n_output_features``. Returns ------- dict A dictionary where: - **Key**: Label of the basis. - - **Value**: the array reshaped to: `(..., n_inputs, n_basis_funcs, ...) + - **Value**: the array reshaped to: ``(..., n_inputs, n_basis_funcs, ...)`` Examples -------- @@ -1464,8 +1464,8 @@ def _set_num_output_features(self, *xi: NDArray) -> Basis: This function computes the number of inputs that are provided to the basis and uses that number, and the n_basis_funcs to calculate the number of output features that - `self.compute_features` will return. These quantities and the input shape (excluding the sample axis) - are stored in `self._n_basis_input` and `self._n_output_features`, and `self._input_shape` + ``self.compute_features`` will return. These quantities and the input shape (excluding the sample axis) + are stored in ``self._n_basis_input`` and ``self._n_output_features``, and ``self._input_shape`` respectively. Parameters @@ -1481,15 +1481,15 @@ def _set_num_output_features(self, *xi: NDArray) -> Basis: Raises ------ ValueError: - If the number of inputs do not match `self._n_basis_input`, if `self._n_basis_input` was + If the number of inputs do not match ``self._n_basis_input``, if ``self._n_basis_input`` was not None. Notes ----- - Once a `compute_features` is called, we enforce that for all subsequent calls of the method, + Once a ``compute_features`` is called, we enforce that for all subsequent calls of the method, the input that the basis receives preserves the shape of all axes, except for the sample axis. This condition guarantees the consistency of the feature axis, and therefore that - `self.split_by_feature` behaves appropriately. + ``self.split_by_feature`` behaves appropriately. """ # Check that the input shape matches expectation @@ -1641,7 +1641,7 @@ def _set_kernel(self, *xi: ArrayLike) -> Basis: Parameters ---------- *xi: - The sample inputs. Unused, necessary to conform to `scikit-learn` API. + The sample inputs. Unused, necessary to conform to ``scikit-learn`` API. Returns ------- @@ -1689,29 +1689,29 @@ def split_by_feature( - $n_i$ represents the number of inputs associated with the i-th component, - $b_i$ represents the number of basis functions in that component. - The specified axis (`axis`) determines where the split occurs, and all other dimensions + The specified axis (``axis``) determines where the split occurs, and all other dimensions remain unchanged. See the example section below for the most common use cases. Parameters ---------- x : The input array to be split, representing concatenated features, coefficients, - or other data. The shape of `x` along the specified axis must match the total - number of features generated by the basis, i.e., `self.n_output_features`. + or other data. The shape of ``x`` along the specified axis must match the total + number of features generated by the basis, i.e., ``self.n_output_features``. **Examples:** - - For a design matrix: `(n_samples, total_n_features)` - - For model coefficients: `(total_n_features,)` or `(total_n_features, n_neurons)`. + - For a design matrix: ``(n_samples, total_n_features)`` + - For model coefficients: ``(total_n_features,)`` or ``(total_n_features, n_neurons)``. axis : int, optional The axis along which to split the features. Defaults to 1. - Use `axis=1` for design matrices (features along columns) and `axis=0` for + Use ``axis=1`` for design matrices (features along columns) and ``axis=0`` for coefficient arrays (features along rows). All other dimensions are preserved. Raises ------ ValueError - If the shape of `x` along the specified axis does not match `self.n_output_features`. + If the shape of ``x`` along the specified axis does not match ``self.n_output_features``. Returns ------- @@ -1724,8 +1724,8 @@ def split_by_feature( (..., n_i, b_i, ...) $$ - - `n_i`: The number of inputs processed by the i-th basis component. - - `b_i`: The number of basis functions for the i-th basis component. + - ``n_i``: The number of inputs processed by the i-th basis component. + - ``b_i``: The number of basis functions for the i-th basis component. These sub-arrays are reshaped along the specified axis, with all other dimensions remaining the same. @@ -1828,7 +1828,7 @@ def _set_kernel(self, *xi: NDArray) -> Basis: Parameters ---------- *xi: - The sample inputs. Unused, necessary to conform to `scikit-learn` API. + The sample inputs. Unused, necessary to conform to ``scikit-learn`` API. Returns ------- @@ -1921,18 +1921,18 @@ class SplineBasis(Basis, abc.ABC): window_size : The window size for convolution. Required if mode is 'conv'. bounds : - The bounds for the basis domain in `mode="eval"`. The default `bounds[0]` and `bounds[1]` are the + The bounds for the basis domain in ``mode="eval"``. The default ``bounds[0]`` and ``bounds[1]`` are the minimum and the maximum of the samples provided when evaluating the basis. If a sample is outside the bounds, the basis will return NaN. label : The label of the basis, intended to be descriptive of the task variable being processed. For example: velocity, position, spike_counts. **kwargs : - Additional keyword arguments passed to `nemos.convolve.create_convolutional_predictor` when - `mode='conv'`; These arguments are used to change the default behavior of the convolution. - For example, changing the `predictor_causality`, which by default is set to `"causal"`. - Note that one cannot change the default value for the `axis` parameter. Basis assumes - that the convolution axis is `axis=0`. + Additional keyword arguments passed to ``nemos.convolve.create_convolutional_predictor`` when + ``mode='conv'``; These arguments are used to change the default behavior of the convolution. + For example, changing the ``predictor_causality``, which by default is set to ``"causal"``. + Note that one cannot change the default value for the ``axis`` parameter. Basis assumes + that the convolution axis is ``axis=0``. Attributes ---------- @@ -2065,7 +2065,7 @@ class MSplineBasis(SplineBasis): splines. This class provides functionality to create M-spline basis functions, allowing - for flexible and smooth modeling of data. It inherits from the `SplineBasis` + for flexible and smooth modeling of data. It inherits from the ``SplineBasis`` abstract class, providing specific implementations for M-splines. Parameters @@ -2083,18 +2083,18 @@ class MSplineBasis(SplineBasis): window_size : The window size for convolution. Required if mode is 'conv'. bounds : - The bounds for the basis domain in `mode="eval"`. The default `bounds[0]` and `bounds[1]` are the + The bounds for the basis domain in ``mode="eval"``. The default ``bounds[0]`` and ``bounds[1]`` are the minimum and the maximum of the samples provided when evaluating the basis. If a sample is outside the bounds, the basis will return NaN. label : The label of the basis, intended to be descriptive of the task variable being processed. For example: velocity, position, spike_counts. **kwargs: - Additional keyword arguments passed to `nemos.convolve.create_convolutional_predictor` when - `mode='conv'`; These arguments are used to change the default behavior of the convolution. - For example, changing the `predictor_causality`, which by default is set to `"causal"`. - Note that one cannot change the default value for the `axis` parameter. Basis assumes - that the convolution axis is `axis=0`. + Additional keyword arguments passed to ``nemos.convolve.create_convolutional_predictor`` when + ``mode='conv'``; These arguments are used to change the default behavior of the convolution. + For example, changing the ``predictor_causality``, which by default is set to ``"causal"``. + Note that one cannot change the default value for the ``axis`` parameter. Basis assumes + that the convolution axis is ``axis=0``. Examples -------- @@ -2202,10 +2202,10 @@ def evaluate_on_grid(self, n_samples: int) -> Tuple[NDArray, NDArray]: ------- X : NDArray A 1D array of uniformly spaced sample points within the domain [0, 1]. - Shape: `(n_samples,)`. + Shape: ``(n_samples,)``. Y : NDArray A 2D array where each row corresponds to the evaluated M-spline basis - function values at the points in X. Shape: `(n_samples, n_basis_funcs)`. + function values at the points in X. Shape: ``(n_samples, n_basis_funcs)``. Examples -------- @@ -2240,27 +2240,27 @@ class BSplineBasis(SplineBasis): n_basis_funcs : Number of basis functions. mode : - The mode of operation. 'eval' for evaluation at sample points, + The mode of operation. ``'eval'`` for evaluation at sample points, 'conv' for convolutional operation. order : - Order of the splines used in basis functions. Must lie within [1, n_basis_funcs]. + Order of the splines used in basis functions. Must lie within ``[1, n_basis_funcs]``. The B-splines have (order-2) continuous derivatives at each interior knot. The higher this number, the smoother the basis representation will be. window_size : The window size for convolution. Required if mode is 'conv'. bounds : - The bounds for the basis domain in `mode="eval"`. The default `bounds[0]` and `bounds[1]` are the + The bounds for the basis domain in ``mode="eval"``. The default ``bounds[0]`` and ``bounds[1]`` are the minimum and the maximum of the samples provided when evaluating the basis. If a sample is outside the bounds, the basis will return NaN. label : The label of the basis, intended to be descriptive of the task variable being processed. For example: velocity, position, spike_counts. **kwargs : - Additional keyword arguments passed to `nemos.convolve.create_convolutional_predictor` when - `mode='conv'`; These arguments are used to change the default behavior of the convolution. - For example, changing the `predictor_causality`, which by default is set to `"causal"`. - Note that one cannot change the default value for the `axis` parameter. Basis assumes - that the convolution axis is `axis=0`. + Additional keyword arguments passed to ``nemos.convolve.create_convolutional_predictor`` when + ``mode='conv'``; These arguments are used to change the default behavior of the convolution. + For example, changing the ``predictor_causality``, which by default is set to ``"causal"``. + Note that one cannot change the default value for the ``axis`` parameter. Basis assumes + that the convolution axis is ``axis=0``. Attributes ---------- @@ -2327,7 +2327,7 @@ def __call__(self, sample_pts: ArrayLike) -> FeatureMatrix: Notes ----- - The evaluation is performed by looping over each element and using `splev` + The evaluation is performed by looping over each element and using ``splev`` from SciPy to compute the basis values. """ sample_pts, _ = min_max_rescale_samples(sample_pts, self.bounds) @@ -2357,7 +2357,7 @@ def evaluate_on_grid(self, n_samples: int) -> Tuple[NDArray, NDArray]: Notes ----- - The evaluation is performed by looping over each element and using `splev` from + The evaluation is performed by looping over each element and using ``splev`` from SciPy to compute the basis values. Examples @@ -2389,18 +2389,18 @@ class CyclicBSplineBasis(SplineBasis): window_size : The window size for convolution. Required if mode is 'conv'. bounds : - The bounds for the basis domain in `mode="eval"`. The default `bounds[0]` and `bounds[1]` are the + The bounds for the basis domain in ``mode="eval"``. The default ``bounds[0]`` and ``bounds[1]`` are the minimum and the maximum of the samples provided when evaluating the basis. If a sample is outside the bounds, the basis will return NaN. label : The label of the basis, intended to be descriptive of the task variable being processed. For example: velocity, position, spike_counts. **kwargs : - Additional keyword arguments passed to `nemos.convolve.create_convolutional_predictor` when - `mode='conv'`; These arguments are used to change the default behavior of the convolution. - For example, changing the `predictor_causality`, which by default is set to `"causal"`. - Note that one cannot change the default value for the `axis` parameter. Basis assumes - that the convolution axis is `axis=0`. + Additional keyword arguments passed to ``nemos.convolve.create_convolutional_predictor`` when + ``mode='conv'``; These arguments are used to change the default behavior of the convolution. + For example, changing the ``predictor_causality``, which by default is set to ``"causal"``. + Note that one cannot change the default value for the ``axis`` parameter. Basis assumes + that the convolution axis is ``axis=0``. Attributes ---------- @@ -2467,7 +2467,7 @@ def __call__( Notes ----- - The evaluation is performed by looping over each element and using `splev` from + The evaluation is performed by looping over each element and using ``splev`` from SciPy to compute the basis values. """ @@ -2522,7 +2522,7 @@ def evaluate_on_grid(self, n_samples: int) -> Tuple[NDArray, NDArray]: Notes ----- - The evaluation is performed by looping over each element and using `splev` from + The evaluation is performed by looping over each element and using ``splev`` from SciPy to compute the basis values. Examples @@ -2554,18 +2554,18 @@ class RaisedCosineBasisLinear(Basis): window_size : The window size for convolution. Required if mode is 'conv'. bounds : - The bounds for the basis domain in `mode="eval"`. The default `bounds[0]` and `bounds[1]` are the + The bounds for the basis domain in ``mode="eval"``. The default ``bounds[0]`` and ``bounds[1]`` are the minimum and the maximum of the samples provided when evaluating the basis. If a sample is outside the bounds, the basis will return NaN. label : The label of the basis, intended to be descriptive of the task variable being processed. For example: velocity, position, spike_counts. **kwargs : - Additional keyword arguments passed to `nemos.convolve.create_convolutional_predictor` when - `mode='conv'`; These arguments are used to change the default behavior of the convolution. - For example, changing the `predictor_causality`, which by default is set to `"causal"`. - Note that one cannot change the default value for the `axis` parameter. Basis assumes - that the convolution axis is `axis=0`. + Additional keyword arguments passed to ``nemos.convolve.create_convolutional_predictor`` when + ``mode='conv'``; These arguments are used to change the default behavior of the convolution. + For example, changing the ``predictor_causality``, which by default is set to ``"causal"``. + Note that one cannot change the default value for the ``axis`` parameter. Basis assumes + that the convolution axis is ``axis=0``. Examples -------- @@ -2746,7 +2746,7 @@ def _check_n_basis_min(self) -> None: class RaisedCosineBasisLog(RaisedCosineBasisLinear): """Represent log-spaced raised cosine basis functions. - Similar to `RaisedCosineBasisLinear` but the basis functions are log-spaced. + Similar to ``RaisedCosineBasisLinear`` but the basis functions are log-spaced. This implementation is based on the cosine bumps used by Pillow et al.[$^{[1]}$](#references) to uniformly tile the internal points of the domain. @@ -2764,24 +2764,24 @@ class RaisedCosineBasisLog(RaisedCosineBasisLinear): larger values resulting in more stretching. As this approaches 0, the transformation becomes linear. enforce_decay_to_zero: - If set to True, the algorithm first constructs a basis with `n_basis_funcs + ceil(width)` elements + If set to True, the algorithm first constructs a basis with ``n_basis_funcs + ceil(width)`` elements and subsequently trims off the extra basis elements. This ensures that the final basis element decays to 0. window_size : The window size for convolution. Required if mode is 'conv'. bounds : - The bounds for the basis domain in `mode="eval"`. The default `bounds[0]` and `bounds[1]` are the + The bounds for the basis domain in ``mode="eval"``. The default ``bounds[0]`` and ``bounds[1]`` are the minimum and the maximum of the samples provided when evaluating the basis. If a sample is outside the bounds, the basis will return NaN. label : The label of the basis, intended to be descriptive of the task variable being processed. For example: velocity, position, spike_counts. **kwargs : - Additional keyword arguments passed to `nemos.convolve.create_convolutional_predictor` when - `mode='conv'`; These arguments are used to change the default behavior of the convolution. - For example, changing the `predictor_causality`, which by default is set to `"causal"`. - Note that one cannot change the default value for the `axis` parameter. Basis assumes - that the convolution axis is `axis=0`. + Additional keyword arguments passed to ``nemos.convolve.create_convolutional_predictor`` when + ``mode='conv'``; These arguments are used to change the default behavior of the convolution. + For example, changing the ``predictor_causality``, which by default is set to ``"causal"``. + Note that one cannot change the default value for the ``axis`` parameter. Basis assumes + that the convolution axis is ``axis=0``. Examples -------- @@ -2942,18 +2942,18 @@ class OrthExponentialBasis(Basis): window_size : The window size for convolution. Required if mode is 'conv'. bounds : - The bounds for the basis domain in `mode="eval"`. The default `bounds[0]` and `bounds[1]` are the + The bounds for the basis domain in ``mode="eval"``. The default ``bounds[0]`` and ``bounds[1]`` are the minimum and the maximum of the samples provided when evaluating the basis. If a sample is outside the bounds, the basis will return NaN. label : The label of the basis, intended to be descriptive of the task variable being processed. For example: velocity, position, spike_counts. **kwargs : - Additional keyword arguments passed to `nemos.convolve.create_convolutional_predictor` when - `mode='conv'`; These arguments are used to change the default behavior of the convolution. - For example, changing the `predictor_causality`, which by default is set to `"causal"`. - Note that one cannot change the default value for the `axis` parameter. Basis assumes - that the convolution axis is `axis=0`. + Additional keyword arguments passed to ``nemos.convolve.create_convolutional_predictor`` when + ``mode='conv'``; These arguments are used to change the default behavior of the convolution. + For example, changing the ``predictor_causality``, which by default is set to ``"causal"``. + Note that one cannot change the default value for the ``axis`` parameter. Basis assumes + that the convolution axis is ``axis=0``. Examples -------- @@ -3225,7 +3225,7 @@ def bspline( Raises ------ AssertionError - If `outer_ok` is False and the sample points lie outside the B-spline knots range. + If ``outer_ok`` is False and the sample points lie outside the B-spline knots range. Notes ----- From ba90747b3e8185741cce0a932be491206ebb67f8 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Tue, 12 Nov 2024 09:35:07 -0500 Subject: [PATCH 008/107] double ticks glm --- src/nemos/glm.py | 110 ++++++++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 54 deletions(-) diff --git a/src/nemos/glm.py b/src/nemos/glm.py index 70ab3a4f..69682f97 100644 --- a/src/nemos/glm.py +++ b/src/nemos/glm.py @@ -72,14 +72,14 @@ class GLM(BaseRegressor): :class:`nemos.solvers._svrg.SVRG` or its proximal variant :class:`nemos.solvers._svrg.ProxSVRG` solver, which take advantage of batched computation. You can change the solver by passing - `"SVRG"` as `solver_name` at model initialization. + ``"SVRG"`` as ``solver_name`` at model initialization. - The performance of the SVRG solver depends critically on the choice of `batch_size` and `stepsize` + The performance of the SVRG solver depends critically on the choice of ``batch_size`` and ``stepsize`` hyperparameters. These parameters control the size of the mini-batches used for gradient computations and the step size for each iteration, respectively. Improper selection of these parameters can lead to slow convergence or even divergence of the optimization process. - To assist with this, for certain GLM configurations, we provide `batch_size` and `stepsize` default + To assist with this, for certain GLM configurations, we provide ``batch_size`` and ``stepsize`` default values that are theoretically guaranteed to ensure fast convergence. Below is a list of the configurations for which we can provide guaranteed default hyperparameters: @@ -111,7 +111,7 @@ class GLM(BaseRegressor): solver_name : Solver to use for model optimization. Defines the optimization scheme and related parameters. The solver must be an appropriate match for the chosen regularizer. - Default is `None`. If no solver specified, one will be chosen based on the regularizer. + Default is ``None``. If no solver specified, one will be chosen based on the regularizer. Please see table above for regularizer/optimizer pairings. solver_kwargs : Optional dictionary for keyword arguments that are passed to the solver when instantiated. @@ -122,7 +122,7 @@ class GLM(BaseRegressor): ---------- intercept_ : Model baseline linked firing rate parameters, e.g. if the link is the logarithm, the baseline - firing rate will be `jnp.exp(model.intercept_)`. + firing rate will be ``jnp.exp(model.intercept_)``. coef_ : Basis coefficients for the model. solver_state_ : @@ -138,7 +138,7 @@ class GLM(BaseRegressor): Raises ------ TypeError - If provided `regularizer` or `observation_model` are not valid. + If provided ``regularizer`` or ``observation_model`` are not valid. Examples -------- @@ -312,8 +312,8 @@ def _predict( Predicts firing rates based on given parameters and design matrix. This function computes the predicted firing rates using the provided parameters - and model design matrix `X`. It is a streamlined version used internally within - optimization routines, where it serves as the loss function. Unlike the `GLM.predict` + and model design matrix ``X``. It is a streamlined version used internally within + optimization routines, where it serves as the loss function. Unlike the ``GLM.predict`` method, it does not perform any input validation, assuming that the inputs are pre-validated. @@ -357,13 +357,13 @@ def predict(self, X: DESIGN_INPUT_TYPE) -> jnp.ndarray: NotFittedError If ``fit`` has not been called first with this instance. ValueError - If `params` is not a JAX pytree of size two. + If ``params`` is not a JAX pytree of size two. ValueError - If weights and bias terms in `params` don't have the expected dimensions. + If weights and bias terms in ``params`` don't have the expected dimensions. ValueError - If `X` is not three-dimensional. + If ``X`` is not three-dimensional. ValueError - If there's an inconsistent number of features between spike basis coefficients and `X`. + If there's an inconsistent number of features between spike basis coefficients and ``X``. Examples -------- @@ -417,7 +417,7 @@ def _predict_and_compute_loss( ) -> jnp.ndarray: r"""Predict the rate and compute the negative log-likelihood against neural activity. - This method computes the negative log-likelihood up to a constant term. Unlike `score`, + This method computes the negative log-likelihood up to a constant term. Unlike ``score``, it does not conduct parameter checks prior to evaluation. Passed directly to the solver, it serves to establish the optimization objective for learning the model parameters. @@ -532,7 +532,7 @@ def score( Therefore, even the Pearson residuals performs poorly as a measure of fit quality, especially for GLM modeling counting data. - Refer to the `nmo.observation_models.Observations` concrete subclasses for the likelihood and + Refer to the ``nmo.observation_models.Observations`` concrete subclasses for the likelihood and pseudo-:math:`R^2` equations. """ @@ -676,20 +676,20 @@ def fit( Raises ------ ValueError - If `init_params` is not of length two. + If ``init_params`` is not of length two. ValueError - If dimensionality of `init_params` are not correct. + If dimensionality of ``init_params`` are not correct. ValueError - If `X` is not two-dimensional. + If ``X`` is not two-dimensional. ValueError - If `y` is not one-dimensional. + If ``y`` is not one-dimensional. ValueError If solver returns at least one NaN parameter, which means it found an invalid solution. Try tuning optimization hyperparameters. TypeError - If `init_params` are not array-like + If ``init_params`` are not array-like TypeError - If `init_params[i]` cannot be converted to jnp.ndarray for all i + If ``init_params[i]`` cannot be converted to jnp.ndarray for all i Examples ------- @@ -855,8 +855,8 @@ def _estimate_resid_degrees_of_freedom( X : The design matrix. n_samples : - The number of samples observed. If not provided, n_samples is set to `X.shape[0]`. If the fit is - batched, the n_samples could be larger than `X.shape[0]`. + The number of samples observed. If not provided, n_samples is set to ``X.shape[0]``. If the fit is + batched, the n_samples could be larger than ``X.shape[0]``. Returns ------- @@ -928,14 +928,14 @@ def initialize_params( Raises ------ ValueError - - If `params` is not of length two. - - If dimensionality of `init_params` are not correct. - - If `X` is not two-dimensional. - - If `y` is not correct (1D for GLM, 2D for populationGLM). + - If ``params`` is not of length two. + - If dimensionality of ``init_params`` are not correct. + - If ``X`` is not two-dimensional. + - If ``y`` is not correct (1D for GLM, 2D for populationGLM). TypeError - - If `params` are not array-like when provided. - - If `init_params[i]` cannot be converted to jnp.ndarray for all i + - If ``params`` are not array-like when provided. + - If ``init_params[i]`` cannot be converted to jnp.ndarray for all i Examples -------- @@ -1062,7 +1062,7 @@ def update( Additional positional arguments to be passed to the solver's update method. n_samples: The tot number of samples. Usually larger than the samples of an indivisual batch, - the `n_samples` are used to estimate the scale parameter of the GLM. + the ``n_samples`` are used to estimate the scale parameter of the GLM. **kwargs Additional keyword arguments to be passed to the solver's update method. @@ -1151,14 +1151,14 @@ class PopulationGLM(GLM): ([SVRG](../solvers/_svrg/#nemos.solvers._svrg.SVRG)) or its proximal variant ([ProxSVRG](../solvers/_svrg/#nemos.solvers._svrg.ProxSVRG)) solver, which take advantage of batched computation. You can change the solver by passing - `"SVRG"` or `"ProxSVRG"` as `solver_name` at model initialization. + ``"SVRG"`` or ``"ProxSVRG"`` as ``solver_name`` at model initialization. - The performance of the SVRG solver depends critically on the choice of `batch_size` and `stepsize` + The performance of the SVRG solver depends critically on the choice of ``batch_size`` and ``stepsize`` hyperparameters. These parameters control the size of the mini-batches used for gradient computations and the step size for each iteration, respectively. Improper selection of these parameters can lead to slow convergence or even divergence of the optimization process. - To assist with this, for certain GLM configurations, we provide `batch_size` and `stepsize` default + To assist with this, for certain GLM configurations, we provide ``batch_size`` and ``stepsize`` default values that are theoretically guaranteed to ensure fast convergence. Below is a list of the configurations for which we can provide guaranteed hyperparameters: @@ -1190,7 +1190,7 @@ class PopulationGLM(GLM): solver_name : Solver to use for model optimization. Defines the optimization scheme and related parameters. The solver must be an appropriate match for the chosen regularizer. - Default is `None`. If no solver specified, one will be chosen based on the regularizer. + Default is ``None``. If no solver specified, one will be chosen based on the regularizer. Please see table above for regularizer/optimizer pairings. solver_kwargs : Optional dictionary for keyword arguments that are passed to the solver when instantiated. @@ -1198,14 +1198,14 @@ class PopulationGLM(GLM): See the jaxopt documentation for details on each solver's kwargs: https://jaxopt.github.io/stable/ feature_mask : Either a matrix of shape (num_features, num_neurons) or a :meth:`nemos.pytrees.FeaturePytree` of 0s and 1s, with - `feature_mask[feature_name]` of shape (num_neurons, ). + ``feature_mask[feature_name]`` of shape (num_neurons, ). The mask will be used to select which features are used as predictors for which neuron. Attributes ---------- intercept_ : Model baseline linked firing rate parameters, e.g. if the link is the logarithm, the baseline - firing rate will be `jnp.exp(model.intercept_)`. + firing rate will be ``jnp.exp(model.intercept_)``. coef_ : Basis coefficients for the model. solver_state_ : @@ -1214,8 +1214,9 @@ class PopulationGLM(GLM): Raises ------ TypeError - - If provided `regularizer` or `observation_model` are not valid.:raw-html:`
` - - If provided `feature_mask` is not an array-like of dimension two.:raw-html:`
` + If provided ``regularizer`` or ``observation_model`` are not valid. + TypeError + If provided ``feature_mask`` is not an array-like of dimension two. Examples -------- @@ -1500,10 +1501,10 @@ def fit( ): """Fit GLM to the activity of a population of neurons. - Fit and store the model parameters as attributes `coef_` and `intercept_`. - Each neuron can have different predictors. The `feature_mask` will determine which + Fit and store the model parameters as attributes ``coef_`` and ``intercept_``. + Each neuron can have different predictors. The ``feature_mask`` will determine which feature will be used for which neurons. See the note below for more information on - the `feature_mask`. + the ``feature_mask``. Parameters ---------- @@ -1522,27 +1523,28 @@ def fit( Raises ------ ValueError - - If `init_params` is not of length two. - - If dimensionality of `init_params` are not correct. - - If `X` is not two-dimensional. - - If `y` is not two-dimensional. - - If the `feature_mask` is not of the right shape. + - If ``init_params`` is not of length two. + - If dimensionality of ``init_params`` are not correct. + - If ``X`` is not two-dimensional. + - If ``y`` is not two-dimensional. + - If the ``feature_mask`` is not of the right shape. - If solver returns at least one NaN parameter, which means it found an invalid solution. Try tuning optimization hyperparameters. TypeError - - If `init_params` are not array-like - - If `init_params[i]` cannot be converted to jnp.ndarray for all i + If ``init_params`` are not array-like + TypeError + If ``init_params[i]`` cannot be converted to jnp.ndarray for all i Notes ----- - The `feature_mask` is used to select features for each neuron, and it is + The ``feature_mask`` is used to select features for each neuron, and it is an NDArray or a :class:`nemos.pytrees.FeaturePytree` of 0s and 1s. In particular, - - If the mask is in array format, feature `i` is a predictor for neuron `j` if - `feature_mask[i, j] == 1`. + - If the mask is in array format, feature ``i`` is a predictor for neuron ``j`` if + ``feature_mask[i, j] == 1``. - - If the mask is a :class:`nemos.pytrees.FeaturePytree`, then `"feature_name"` is a predictor of neuron `j` if - `feature_mask["feature_name"][j] == 1`. + - If the mask is a :class:``nemos.pytrees.FeaturePytree``, then ``"feature_name"`` is a predictor of neuron ``j`` if + ``feature_mask["feature_name"][j] == 1``. Examples -------- @@ -1590,8 +1592,8 @@ def _predict( Predicts firing rates based on given parameters and design matrix. This function computes the predicted firing rates using the provided parameters, the feature - mask and model design matrix `X`. It is a streamlined version used internally within - optimization routines, where it serves as the loss function. Unlike the `GLM.predict` + mask and model design matrix ``X``. It is a streamlined version used internally within + optimization routines, where it serves as the loss function. Unlike the ``GLM.predict`` method, it does not perform any input validation, assuming that the inputs are pre-validated. The parameters are first element-wise multiplied with the mask, then the canonical linear-non-linear GLM map is applied. From fb16a489a1ed76e87708ef018d38b24dc53401df Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Tue, 12 Nov 2024 09:49:03 -0500 Subject: [PATCH 009/107] fixed examples --- src/nemos/glm.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/nemos/glm.py b/src/nemos/glm.py index 69682f97..b4670893 100644 --- a/src/nemos/glm.py +++ b/src/nemos/glm.py @@ -388,7 +388,7 @@ def predict(self, X: DESIGN_INPUT_TYPE) -> jnp.ndarray: :meth:`nemos.glm.GLM.simulate` Simulate neural activity in response to a feed-forward input (feed-forward only). - :meth:`nemos.simulation.simulate_recurrent` + :func:`nemos.simulation.simulate_recurrent` Simulate neural activity in response to a feed-forward input using the GLM as a recurrent network (feed-forward + coupling). """ @@ -689,19 +689,17 @@ def fit( TypeError If ``init_params`` are not array-like TypeError - If ``init_params[i]`` cannot be converted to jnp.ndarray for all i + If ``init_params[i]`` cannot be converted to ``jnp.ndarray`` for all ``i`` Examples ------- >>> # example input >>> import numpy as np >>> X, y = np.random.normal(size=(10, 2)), np.random.poisson(size=10) - >>> # fit a ridge regression Poisson GLM >>> import nemos as nmo >>> model = nmo.glm.GLM(regularizer="Ridge", regularizer_strength=0.1) >>> model = model.fit(X, y) - >>> # get model weights and intercept >>> model_weights = model.coef_ >>> model_intercept = model.intercept_ @@ -804,12 +802,10 @@ def simulate( >>> # example input >>> import numpy as np >>> X, y = np.random.normal(size=(10, 2)), np.random.poisson(size=10) - >>> # define and fit model >>> import nemos as nmo >>> model = nmo.glm.GLM() >>> model = model.fit(X, y) - >>> # generate spikes and rates >>> random_key = jax.random.key(123) >>> Xnew = np.random.normal(size=(20, X.shape[1])) @@ -1552,7 +1548,6 @@ def fit( >>> import jax.numpy as jnp >>> import numpy as np >>> from nemos.glm import PopulationGLM - >>> # Define predictors (X), weights, and neural activity (y) >>> num_samples, num_features, num_neurons = 100, 3, 2 >>> X = np.random.normal(size=(num_samples, num_features)) @@ -1560,10 +1555,8 @@ def fit( >>> weights = np.array([[ 0.5, 0. ], [-0.5, -0.5], [ 0. , 1. ]]) >>> # Output y simulates a Poisson distribution based on a linear model between features X and wegihts >>> y = np.random.poisson(np.exp(X.dot(weights))) - >>> # Define a feature mask, shape (num_features, num_neurons) >>> feature_mask = jnp.array([[1, 0], [1, 1], [0, 1]]) - >>> # Create and fit the model >>> model = PopulationGLM(feature_mask=feature_mask).fit(X, y) >>> print(model.coef_.shape) From a90a4322f0f6254b70860ae7b1808a9b5dffd1f7 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Tue, 12 Nov 2024 09:51:23 -0500 Subject: [PATCH 010/107] fixed examples --- src/nemos/glm.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/nemos/glm.py b/src/nemos/glm.py index b4670893..18a73133 100644 --- a/src/nemos/glm.py +++ b/src/nemos/glm.py @@ -143,15 +143,12 @@ class GLM(BaseRegressor): Examples -------- >>> import nemos as nmo - >>> # define single neuron GLM model >>> model = nmo.glm.GLM() >>> print("Regularizer type: ", type(model.regularizer)) Regularizer type: >>> print("Observation model: ", type(model.observation_model)) Observation model: - - >>> # define GLM model of PoissonObservations model with soft-plus NL >>> observation_models = nmo.observation_models.PoissonObservations(jax.nn.softplus) >>> model = nmo.glm.GLM(observation_model=observation_models, solver_name="LBFGS") @@ -370,12 +367,10 @@ def predict(self, X: DESIGN_INPUT_TYPE) -> jnp.ndarray: >>> # example input >>> import numpy as np >>> X, y = np.random.normal(size=(10, 2)), np.random.poisson(size=10) - >>> # define and fit a GLM >>> import nemos as nmo >>> model = nmo.glm.GLM() >>> model = model.fit(X, y) - >>> # predict new spike data >>> Xnew = np.random.normal(size=(20, X.shape[1])) >>> predicted_spikes = model.predict(Xnew) @@ -489,14 +484,11 @@ def score( >>> # example input >>> import numpy as np >>> X, y = np.random.normal(size=(10, 2)), np.random.poisson(size=10) - >>> import nemos as nmo >>> model = nmo.glm.GLM() >>> model = model.fit(X, y) - >>> # get model score >>> log_likelihood_score = model.score(X, y) - >>> # get a pseudo-R2 score >>> pseudo_r2_score = model.score(X, y, score_type='pseudo-r2-McFadden') @@ -1084,6 +1076,7 @@ def update( >>> params = glm_instance.coef_, glm_instance.intercept_ >>> opt_state = glm_instance.solver_state_ >>> new_params, new_opt_state = glm_instance.update(params, opt_state, X, y) + """ # find non-nans is_valid = tree_utils.get_valid_multitree(X, y) @@ -1248,12 +1241,10 @@ class PopulationGLM(GLM): >>> rate = np.exp(X["feature_1"].dot(weights["feature_1"]) + X["feature_2"].dot(weights["feature_2"])) >>> y = np.random.poisson(rate) >>> # Define a feature mask with arrays of shape (num_neurons, ) - >>> feature_mask = FeaturePytree(feature_1=jnp.array([0, 1]), feature_2=jnp.array([1, 0])) >>> print(feature_mask) feature_1: shape (2,), dtype int32 feature_2: shape (2,), dtype int32 - >>> # Fit a PopulationGLM >>> model = PopulationGLM(feature_mask=feature_mask).fit(X, y) >>> # Coefficients are stored in a dictionary with keys the feature labels From 13473518b37fe7dff82ed0660d80509ae1888e93 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Tue, 12 Nov 2024 11:57:08 -0500 Subject: [PATCH 011/107] fixed examples --- docs/api_guide.rst | 15 +-- docs/assets/stylesheets/custom.css | 2 + docs/conf.py | 20 +++- docs/index.md | 2 +- src/nemos/basis.py | 149 ++++++++++++----------------- 5 files changed, 92 insertions(+), 96 deletions(-) diff --git a/docs/api_guide.rst b/docs/api_guide.rst index 11f88364..c06e04e7 100644 --- a/docs/api_guide.rst +++ b/docs/api_guide.rst @@ -1,27 +1,28 @@ .. _api_ref: API Guide ---------- - -.. rubric:: The nemos.glm module +========= +The ``nemos.glm`` module +------------------------ .. currentmodule:: nemos.glm .. autosummary:: - :toctree: stubs + :toctree: generated/glm :recursive: :nosignatures: GLM PopulationGLM -.. rubric:: The nemos.basis module +The ``nemos.basis`` module +-------------------------- .. currentmodule:: nemos.basis .. autosummary:: - :toctree: stubs + :toctree: generated/basis :recursive: :nosignatures: @@ -33,4 +34,4 @@ API Guide RaisedCosineBasisLog AdditiveBasis MultiplicativeBasis - TransformerBasis \ No newline at end of file + TransformerBasis diff --git a/docs/assets/stylesheets/custom.css b/docs/assets/stylesheets/custom.css index 75a1e54b..ec3c1f7f 100644 --- a/docs/assets/stylesheets/custom.css +++ b/docs/assets/stylesheets/custom.css @@ -71,10 +71,12 @@ html[data-theme=light]{ margin-top: auto; /* Pushes the footer content to the bottom */ } + .sphinxsidebar .globaltoc { display: none; } + /* Add vertical spacing between cards */ .sd-col { margin-bottom: 20px; /* Adjust this value as needed for desired spacing */ diff --git a/docs/conf.py b/docs/conf.py index cd7334c2..f4e35720 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -10,6 +10,21 @@ import sys, os from pathlib import Path +# conf.py +# def strip_class_name_from_methods(app, what, name, obj, options, signature, return_annotation): +# # Check if it’s a method in a class and remove the class prefix +# if what == "method" and "." in name: +# # Only use the method part of the full name +# method_name = name.split(".")[-1] +# +# # Emit the updated signature and return annotation without class name +# return method_name + signature, return_annotation +# return signature, return_annotation +# +# def setup(app): +# app.connect("autodoc-process-signature", strip_class_name_from_methods) + + sys.path.insert(0, str(Path('..', 'src').resolve())) sys.path.insert(0, os.path.abspath('sphinxext')) @@ -72,6 +87,7 @@ numpydoc_show_class_members = True autodoc_default_options = { 'members': True, + 'inherited-members': True, 'undoc-members': True, 'show-inheritance': True, } @@ -89,9 +105,10 @@ napoleon_use_param = True napoleon_use_rtype = True -autodoc_typehints = "none" # Use "description" to place hints in the description, or "signature" for inline hints +autodoc_typehints = "description" # Use "description" to place hints in the description autodoc_type_aliases = { "ArrayLike": "ArrayLike", + "NDArray": "NDArray" } numfig = True @@ -119,6 +136,7 @@ ], "show_prev_next": True, "header_links_before_dropdown": 5, + "navigation_depth": 2, } html_context = { diff --git a/docs/index.md b/docs/index.md index b8c4b8f4..54d3cf72 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,7 +6,7 @@ ```{toctree} -:maxdepth: 1 +:maxdepth: 2 :hidden: Install diff --git a/src/nemos/basis.py b/src/nemos/basis.py index 5491fcbd..f829d018 100644 --- a/src/nemos/basis.py +++ b/src/nemos/basis.py @@ -132,7 +132,6 @@ class TransformerBasis: >>> from sklearn.model_selection import GridSearchCV >>> import numpy as np >>> np.random.seed(123) - >>> # Generate data >>> num_samples, num_features = 10000, 1 >>> x = np.random.normal(size=(num_samples, )) # raw time series @@ -140,7 +139,6 @@ class TransformerBasis: >>> features = basis.compute_features(x) # basis transformed time series >>> weights = np.random.normal(size=basis.n_basis_funcs) # true weights >>> y = np.random.poisson(np.exp(features.dot(weights))) # spike counts - >>> # transformer can be used in pipelines >>> transformer = TransformerBasis(basis) >>> pipeline = Pipeline([ ("compute_features", transformer), ("glm", GLM()),]) @@ -201,10 +199,8 @@ def fit(self, X: FeatureMatrix, y=None): -------- >>> import numpy as np >>> from nemos.basis import MSplineBasis, TransformerBasis - >>> # Example input >>> X = np.random.normal(size=(100, 2)) - >>> # Define and fit tranformation basis >>> basis = MSplineBasis(10) >>> transformer = TransformerBasis(basis) @@ -233,21 +229,17 @@ def transform(self, X: FeatureMatrix, y=None) -> FeatureMatrix: -------- >>> import numpy as np >>> from nemos.basis import MSplineBasis, TransformerBasis - >>> # Example input >>> X = np.random.normal(size=(10000, 2)) - >>> # Define and fit tranformation basis >>> basis = MSplineBasis(10, mode="conv", window_size=200) >>> transformer = TransformerBasis(basis) >>> # Before calling `fit` the convolution kernel is not set >>> transformer.kernel_ - >>> transformer_fitted = transformer.fit(X) >>> # Now the convolution kernel is initialized and has shape (window_size, n_basis_funcs) >>> transformer_fitted.kernel_.shape (200, 10) - >>> # Transform basis >>> feature_transformed = transformer.transform(X[:, 0:1]) """ @@ -280,14 +272,11 @@ def fit_transform(self, X: FeatureMatrix, y=None) -> FeatureMatrix: -------- >>> import numpy as np >>> from nemos.basis import MSplineBasis, TransformerBasis - >>> # Example input >>> X = np.random.normal(size=(100, 1)) - >>> # Define tranformation basis >>> basis = MSplineBasis(10) >>> transformer = TransformerBasis(basis) - >>> # Fit and transform basis >>> feature_transformed = transformer.fit_transform(X) """ @@ -397,7 +386,6 @@ def set_params(self, **parameters) -> TransformerBasis: >>> from nemos.basis import BSplineBasis, MSplineBasis, TransformerBasis >>> basis = MSplineBasis(10) >>> transformer_basis = TransformerBasis(basis=basis) - >>> # setting parameters of _basis is allowed >>> print(transformer_basis.set_params(n_basis_funcs=8).n_basis_funcs) 8 @@ -768,8 +756,8 @@ def _compute_features(self, *xi: ArrayLike) -> FeatureMatrix: ------- : A matrix with the transformed features. The shape of the output depends on the operation mode: - - If ``mode == 'eval'``, the basis evaluated at the samples, or $b_i(*xi)$, where $b_i$ is a - basis element. xi[k] must be a one-dimensional array or a pynapple Tsd. + - If ``mode == 'eval'``, the basis evaluated at the samples, or :math:`b_i(*xi)`, where :math:`b_i` + is a basis element. ``xi[k]`` must be a one-dimensional array or a pynapple Tsd. - If ``mode == 'conv'``, a bank of basis filters (created by calling fit) is convolved with the samples. Samples can be a NDArray, or a pynapple Tsd/TsdFrame/TsdTensor. All the dimensions @@ -830,7 +818,6 @@ def compute_features(self, *xi: ArrayLike) -> FeatureMatrix: -------- >>> import numpy as np >>> from nemos.basis import BSplineBasis - >>> # Generate data >>> num_samples = 10000 >>> X = np.random.normal(size=(num_samples, )) # raw time series @@ -983,7 +970,7 @@ def _check_has_kernel(self) -> None: def evaluate_on_grid(self, *n_samples: int) -> Tuple[Tuple[NDArray], NDArray]: """Evaluate the basis set on a grid of equi-spaced sample points. - The i-th axis of the grid will be sampled with n_samples[i] equi-spaced points. + The i-th axis of the grid will be sampled with ``n_samples[i]`` equi-spaced points. The method uses numpy.meshgrid with ``indexing="ij"``, returning matrix indexing instead of the default cartesian indexing, see Notes. @@ -998,10 +985,10 @@ def evaluate_on_grid(self, *n_samples: int) -> Tuple[Tuple[NDArray], NDArray]: *Xs : A tuple of arrays containing the meshgrid values, one element for each of the n dimension of the grid, where n equals to the number of inputs. - The size of Xs[i] is (n_samples[0], ... , n_samples[n]). + The size of ``Xs[i]`` is ``(n_samples[0], ... , n_samples[n])``. Y : The basis function evaluated at the samples, - shape (n_samples[0], ... , n_samples[n], number of basis). + shape ``(n_samples[0], ... , n_samples[n], number of basis)``. Raises ------ @@ -1012,10 +999,10 @@ def evaluate_on_grid(self, *n_samples: int) -> Tuple[Tuple[NDArray], NDArray]: Notes ----- - Setting "indexing = 'ij'" returns a meshgrid with matrix indexing. In the N-D case with inputs of size - $M_1,...,M_N$, outputs are of shape $(M_1, M_2, M_3, ....,M_N)$. + Setting ``indexing = 'ij'`` returns a meshgrid with matrix indexing. In the N-D case with inputs of size + :math:`M_1,...,M_N`, outputs are of shape :math:`(M_1, M_2, M_3, ....,M_N)`. This differs from the numpy.meshgrid default, which uses Cartesian indexing. - For the same input, Cartesian indexing would return an output of shape $(M_2, M_1, M_3, ....,M_N)$. + For the same input, Cartesian indexing would return an output of shape :math:`(M_2, M_1, M_3, ....,M_N)`. Examples -------- @@ -1524,7 +1511,7 @@ class AdditiveBasis(Basis): Attributes ---------- - n_basis_funcs : int + n_basis_funcs : Number of basis functions. Examples @@ -1533,16 +1520,15 @@ class AdditiveBasis(Basis): >>> import numpy as np >>> import nemos as nmo >>> X = np.random.normal(size=(30, 2)) - >>> # define two basis objects and add them >>> basis_1 = nmo.basis.BSplineBasis(10) >>> basis_2 = nmo.basis.RaisedCosineBasisLinear(15) >>> additive_basis = basis_1 + basis_2 - >>> # can add another basis to the AdditiveBasis object >>> X = np.random.normal(size=(30, 3)) >>> basis_3 = nmo.basis.RaisedCosineBasisLog(100) >>> additive_basis_2 = additive_basis + basis_3 + """ def __init__(self, basis1: Basis, basis2: Basis) -> None: @@ -1666,28 +1652,26 @@ def split_by_feature( **How It Works:** - Suppose the basis is made up of **m components**, each with $b_i$ basis functions and $n_i$ inputs. - The total number of features, $N$, is calculated as: + Suppose the basis is made up of **m components**, each with :math:`b_i` basis functions and :math:`n_i` inputs. + The total number of features, :math:`N`, is calculated as: - $$ - N = b_1 \cdot n_1 + b_2 \cdot n_2 + \ldots + b_m \cdot n_m - $$ + .. math:: + N = b_1 \cdot n_1 + b_2 \cdot n_2 + \ldots + b_m \cdot n_m - This method splits any axis of length $N$ into sub-arrays, one for each basis component. + This method splits any axis of length :math:`N` into sub-arrays, one for each basis component. The sub-array for the i-th basis component is reshaped into dimensions - $(n_i, b_i)$. + :math:`(n_i, b_i)`. - For example, if the array shape is $(1, 2, N, 4, 5)$, then each split sub-array will have shape: + For example, if the array shape is :math:`(1, 2, N, 4, 5)`, then each split sub-array will have shape: - $$ - (1, 2, n_i, b_i, 4, 5) - $$ + .. math:: + (1, 2, n_i, b_i, 4, 5) where: - - $n_i$ represents the number of inputs associated with the i-th component, - - $b_i$ represents the number of basis functions in that component. + - :math:`n_i` represents the number of inputs associated with the i-th component, + - :math:`b_i` represents the number of basis functions in that component. The specified axis (``axis``) determines where the split occurs, and all other dimensions remain unchanged. See the example section below for the most common use cases. @@ -1720,12 +1704,11 @@ def split_by_feature( - **Keys**: Labels of the additive basis components. - **Values**: Sub-arrays corresponding to each component. Each sub-array has the shape: - $$ - (..., n_i, b_i, ...) - $$ + .. math:: + (..., n_i, b_i, ...) - - ``n_i``: The number of inputs processed by the i-th basis component. - - ``b_i``: The number of basis functions for the i-th basis component. + - ``n_i``: The number of inputs processed by the i-th basis component. + - ``b_i``: The number of basis functions for the i-th basis component. These sub-arrays are reshaped along the specified axis, with all other dimensions remaining the same. @@ -1783,7 +1766,7 @@ class MultiplicativeBasis(Basis): Attributes ---------- - n_basis_funcs : int + n_basis_funcs : Number of basis functions. Examples @@ -1792,12 +1775,10 @@ class MultiplicativeBasis(Basis): >>> import numpy as np >>> import nemos as nmo >>> X = np.random.normal(size=(30, 3)) - >>> # define two basis and multiply >>> basis_1 = nmo.basis.BSplineBasis(10) >>> basis_2 = nmo.basis.RaisedCosineBasisLinear(15) >>> multiplicative_basis = basis_1 * basis_2 - >>> # Can multiply or add another basis to the AdditiveBasis object >>> # This will cause the number of output features of the result basis to grow accordingly >>> basis_3 = nmo.basis.RaisedCosineBasisLog(100) @@ -2056,7 +2037,7 @@ def _check_n_basis_min(self) -> None: class MSplineBasis(SplineBasis): r""" - M-spline[$^{[1]}$](#references) basis functions for modeling and data transformation. + M-spline [1]_ basis functions for modeling and data transformation. M-splines are a type of spline basis function used for smooth curve fitting and data representation. They are positive and integrate to one, making them @@ -2106,16 +2087,16 @@ class MSplineBasis(SplineBasis): >>> sample_points = linspace(0, 1, 100) >>> basis_functions = mspline_basis(sample_points) - # References - ------------ - [1] Ramsay, J. O. (1988). Monotone regression splines in action. Statistical science, + References + ---------- + .. [1] Ramsay, J. O. (1988). Monotone regression splines in action. Statistical science, 3(4), 425-441. Notes ----- - MSplines must integrate to 1 over their domain (the area under the curve is 1). Therefore, if the domain - (x-axis) of an MSpline basis is expanded by a factor of $\alpha$, the values on the co-domain (y-axis) values - will shrink by a factor of $1/\alpha$. + ``MSplines`` must integrate to 1 over their domain (the area under the curve is 1). Therefore, if the domain + (x-axis) of an MSpline basis is expanded by a factor of :math:`\alpha`, the values on the co-domain (y-axis) values + will shrink by a factor of :math:`1/\alpha`. For example, over the standard bounds of (0, 1), the maximum value of the MSpline is 18. If we set the bounds to (0, 2), the maximum value will be 9, i.e., 18 / 2. """ @@ -2277,7 +2258,6 @@ class BSplineBasis(SplineBasis): -------- >>> from numpy import linspace >>> from nemos.basis import BSplineBasis - >>> bspline_basis = BSplineBasis(n_basis_funcs=5, order=3) >>> sample_points = linspace(0, 1, 100) >>> basis_functions = bspline_basis(sample_points) @@ -2350,10 +2330,10 @@ def evaluate_on_grid(self, n_samples: int) -> Tuple[NDArray, NDArray]: Returns ------- X : - Array of shape (n_samples,) containing the equi-spaced sample + Array of shape ``(n_samples,)`` containing the equi-spaced sample points where we've evaluated the basis. basis_funcs : - Raised cosine basis functions, shape (n_samples, n_basis_funcs) + Raised cosine basis functions, shape ``(n_samples, n_basis_funcs)`` Notes ----- @@ -2404,17 +2384,16 @@ class CyclicBSplineBasis(SplineBasis): Attributes ---------- - n_basis_funcs : int - Number of basis functions. - order : int - Order of the splines used in basis functions. + n_basis_funcs : + Number of basis functions, int. + order : + Order of the splines used in basis functions, int. Examples -------- >>> from numpy import linspace >>> from nemos.basis import CyclicBSplineBasis >>> X = np.random.normal(size=(1000, 1)) - >>> cyclic_basis = CyclicBSplineBasis(n_basis_funcs=5, order=3, mode="conv", window_size=10) >>> sample_points = linspace(0, 1, 100) >>> basis_functions = cyclic_basis(sample_points) @@ -2515,10 +2494,10 @@ def evaluate_on_grid(self, n_samples: int) -> Tuple[NDArray, NDArray]: Returns ------- X : - Array of shape (n_samples,) containing the equi-spaced sample + Array of shape ``(n_samples,)`` containing the equi-spaced sample points where we've evaluated the basis. basis_funcs : - Raised cosine basis functions, shape (n_samples, n_basis_funcs) + Raised cosine basis functions, shape ``(n_samples, n_basis_funcs)`` Notes ----- @@ -2539,7 +2518,7 @@ def evaluate_on_grid(self, n_samples: int) -> Tuple[NDArray, NDArray]: class RaisedCosineBasisLinear(Basis): """Represent linearly-spaced raised cosine basis functions. - This implementation is based on the cosine bumps used by Pillow et al.[$^{[1]}$](#references) + This implementation is based on the cosine bumps used by Pillow et al. [1]_ to uniformly tile the internal points of the domain. Parameters @@ -2572,14 +2551,13 @@ class RaisedCosineBasisLinear(Basis): >>> from numpy import linspace >>> from nemos.basis import RaisedCosineBasisLinear >>> X = np.random.normal(size=(1000, 1)) - >>> cosine_basis = RaisedCosineBasisLinear(n_basis_funcs=5, mode="conv", window_size=10) >>> sample_points = linspace(0, 1, 100) >>> basis_functions = cosine_basis(sample_points) - # References - ------------ - [1] Pillow, J. W., Paninski, L., Uzzel, V. J., Simoncelli, E. P., & J., + References + ---------- + .. [1] Pillow, J. W., Paninski, L., Uzzel, V. J., Simoncelli, E. P., & J., C. E. (2005). Prediction and decoding of retinal ganglion cell responses with a probabilistic spiking model. Journal of Neuroscience, 25(47), 11003–11013. http://dx.doi.org/10.1523/jneurosci.3305-05.2005 @@ -2711,10 +2689,10 @@ def evaluate_on_grid(self, n_samples: int) -> Tuple[NDArray, NDArray]: Returns ------- X : - Array of shape (n_samples,) containing the equi-spaced sample + Array of shape ``(n_samples,)`` containing the equi-spaced sample points where we've evaluated the basis. basis_funcs : - Raised cosine basis functions, shape (n_samples, n_basis_funcs) + Raised cosine basis functions, shape ``(n_samples, n_basis_funcs)`` Examples -------- @@ -2747,7 +2725,7 @@ class RaisedCosineBasisLog(RaisedCosineBasisLinear): """Represent log-spaced raised cosine basis functions. Similar to ``RaisedCosineBasisLinear`` but the basis functions are log-spaced. - This implementation is based on the cosine bumps used by Pillow et al.[$^{[1]}$](#references) + This implementation is based on the cosine bumps used by Pillow et al. [1]_ to uniformly tile the internal points of the domain. Parameters @@ -2788,14 +2766,13 @@ class RaisedCosineBasisLog(RaisedCosineBasisLinear): >>> from numpy import linspace >>> from nemos.basis import RaisedCosineBasisLog >>> X = np.random.normal(size=(1000, 1)) - >>> cosine_basis = RaisedCosineBasisLog(n_basis_funcs=5, mode="conv", window_size=10) >>> sample_points = linspace(0, 1, 100) >>> basis_functions = cosine_basis(sample_points) - # References - ------------ - [1] Pillow, J. W., Paninski, L., Uzzel, V. J., Simoncelli, E. P., & J., + References + ---------- + .. [1] Pillow, J. W., Paninski, L., Uzzel, V. J., Simoncelli, E. P., & J., C. E. (2005). Prediction and decoding of retinal ganglion cell responses with a probabilistic spiking model. Journal of Neuroscience, 25(47), 11003–11013. http://dx.doi.org/10.1523/jneurosci.3305-05.2005 @@ -2935,12 +2912,12 @@ class OrthExponentialBasis(Basis): n_basis_funcs Number of basis functions. decay_rates : - Decay rates of the exponentials, shape (n_basis_funcs,). + Decay rates of the exponentials, shape ``(n_basis_funcs,)``. mode : - The mode of operation. 'eval' for evaluation at sample points, - 'conv' for convolutional operation. + The mode of operation. ``'eval'`` for evaluation at sample points, + ``'conv'`` for convolutional operation. window_size : - The window size for convolution. Required if mode is 'conv'. + The window size for convolution. Required if mode is ``'conv'``. bounds : The bounds for the basis domain in ``mode="eval"``. The default ``bounds[0]`` and ``bounds[1]`` are the minimum and the maximum of the samples provided when evaluating the basis. @@ -2971,8 +2948,8 @@ class OrthExponentialBasis(Basis): def __init__( self, n_basis_funcs: int, - decay_rates: NDArray[np.floating], - mode="eval", + decay_rates: NDArray, + mode: Literal["eval", "conv"] = "eval", window_size: Optional[int] = None, bounds: Optional[Tuple[float, float]] = None, label: Optional[str] = "OrthExponentialBasis", @@ -3074,14 +3051,14 @@ def __call__( Parameters ---------- sample_pts - Spacing for basis functions, holding elements on the interval [0, - inf), shape (n_samples,). + Spacing for basis functions, holding elements on the interval :math:`[0,inf)`, + shape ``(n_samples,)``. Returns ------- basis_funcs Evaluated exponentially decaying basis functions, numerically - orthogonalized, shape (n_samples, n_basis_funcs) + orthogonalized, shape ``(n_samples, n_basis_funcs)``. """ self._check_sample_size(sample_pts) @@ -3115,11 +3092,11 @@ def evaluate_on_grid(self, n_samples: int) -> Tuple[NDArray, NDArray]: Returns ------- X : - Array of shape (n_samples,) containing the equi-spaced sample + Array of shape ``(n_samples,)`` containing the equi-spaced sample points where we've evaluated the basis. basis_funcs : Evaluated exponentially decaying basis functions, numerically - orthogonalized, shape (n_samples, n_basis_funcs) + orthogonalized, shape ``(n_samples, n_basis_funcs)`` Examples -------- @@ -3159,7 +3136,6 @@ def mspline(x: NDArray, k: int, i: int, T: NDArray) -> NDArray: >>> import numpy as np >>> from numpy import linspace >>> from nemos.basis import mspline - >>> sample_points = linspace(0, 1, 100) >>> mspline_eval = mspline(x=sample_points, k=3, i=2, T=np.random.rand(7)) # define a cubic M-spline >>> mspline_eval.shape @@ -3236,7 +3212,6 @@ def bspline( >>> import numpy as np >>> from numpy import linspace >>> from nemos.basis import bspline - >>> sample_points = linspace(0, 1, 100) >>> knots = np.array([0, 0, 0, 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 1, 1, 1, 1]) >>> bspline_eval = bspline(sample_points, knots) # define a cubic B-spline From bf9c093546bc3a357d998bee33efb27a2dd20962 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Tue, 12 Nov 2024 12:44:50 -0500 Subject: [PATCH 012/107] improved docstrings --- docs/_templates/autosummary/class.rst | 33 ++++++++++++++ src/nemos/base_regressor.py | 6 +-- src/nemos/glm.py | 65 ++++++++++++++------------- tests/test_base_class.py | 2 +- tests/test_glm.py | 8 ++-- 5 files changed, 76 insertions(+), 38 deletions(-) create mode 100644 docs/_templates/autosummary/class.rst diff --git a/docs/_templates/autosummary/class.rst b/docs/_templates/autosummary/class.rst new file mode 100644 index 00000000..0d066e33 --- /dev/null +++ b/docs/_templates/autosummary/class.rst @@ -0,0 +1,33 @@ +{{ fullname | escape | underline }} + +.. currentmodule:: {{ module }} + +.. autoclass:: {{ objname }} + :members: + :inherited-members: + +{% block methods %} + .. automethod:: __init__ + + {% if methods %} + .. rubric:: Methods + + .. autosummary:: + :toctree: ./ + {% for item in methods %} + ~{{ objname }}.{{ item }} + {%- endfor %} + {% endif %} +{% endblock %} + +{% block attributes %} + {% if attributes %} + .. rubric:: Attributes + + .. autosummary:: + :toctree: ./ + {% for item in attributes %} + ~{{ objname }}.{{ item }} + {%- endfor %} + {% endif %} +{% endblock %} diff --git a/src/nemos/base_regressor.py b/src/nemos/base_regressor.py index c60da8da..692f7067 100644 --- a/src/nemos/base_regressor.py +++ b/src/nemos/base_regressor.py @@ -608,7 +608,7 @@ def _get_solver_class(solver_name: str): return solver_class - def optimize_solver_params(self, X: DESIGN_INPUT_TYPE, y: jnp.ndarray) -> dict: + def _optimize_solver_params(self, X: DESIGN_INPUT_TYPE, y: jnp.ndarray) -> dict: """ Compute and update solver parameters with optimal defaults if available. @@ -635,7 +635,7 @@ def optimize_solver_params(self, X: DESIGN_INPUT_TYPE, y: jnp.ndarray) -> dict: # get the model specific configs compute_defaults, compute_l_smooth, strong_convexity = ( - self.get_optimal_solver_params_config() + self._get_optimal_solver_params_config() ) if compute_defaults and compute_l_smooth: # Check if the user has provided batch size or stepsize, or else use None @@ -658,6 +658,6 @@ def optimize_solver_params(self, X: DESIGN_INPUT_TYPE, y: jnp.ndarray) -> dict: return new_solver_kwargs @abstractmethod - def get_optimal_solver_params_config(self): + def _get_optimal_solver_params_config(self): """Return the functions for computing default step and batch size for the solver.""" pass diff --git a/src/nemos/glm.py b/src/nemos/glm.py index 18a73133..d762a7f4 100644 --- a/src/nemos/glm.py +++ b/src/nemos/glm.py @@ -184,7 +184,7 @@ def __init__( @property def observation_model(self) -> Union[None, obs.Observations]: - """Getter for the observation_model attribute.""" + """Getter for the ``observation_model`` attribute.""" return self._observation_model @observation_model.setter @@ -342,12 +342,12 @@ def predict(self, X: DESIGN_INPUT_TYPE) -> jnp.ndarray: Parameters ---------- X : - Predictors, array of shape (n_time_bins, n_features) or pytree of same. + Predictors, array of shape ``(n_time_bins, n_features)`` or pytree of same. Returns ------- : - The predicted rates with shape (n_time_bins, ). + The predicted rates with shape ``(n_time_bins, )``. Raises ------ @@ -446,7 +446,7 @@ def score( r"""Evaluate the goodness-of-fit of the model to the observed neural data. This method computes the goodness-of-fit score, which can either be the mean - log-likelihood or of two versions of the pseudo-R^2. + log-likelihood or of two versions of the pseudo-:math:`R^2`. The scoring process includes validation of input compatibility with the model's parameters, ensuring that the model has been previously fitted and the input data are appropriate for scoring. A higher score indicates a better fit of the model @@ -456,11 +456,11 @@ def score( Parameters ---------- X : - The exogenous variables. Shape (n_time_bins, n_features) + The exogenous variables. Shape ``(n_time_bins, n_features)``. y : - Neural activity. Shape (n_time_bins, ). + Neural activity. Shape ``(n_time_bins, )``. score_type : - Type of scoring: either log-likelihood or pseudo-r2. + Type of scoring: either log-likelihood or pseudo-:math:`R^2`. aggregate_sample_scores : Function that aggregates the score of all samples. @@ -507,16 +507,17 @@ def score( Why does the traditional :math:`R^2` is usually a poor measure of performance in GLMs? 1. In the context of GLMs the variance and the mean of the observations are related. - Ignoring the relation between them can result in underestimating the model - performance; for instance, when we model a Poisson variable with large mean we expect an - equally large variance. In this scenario, even if our model perfectly captures the mean, - the high-variance will result in large residuals and low :math:`R^2`. - Additionally, when the mean of the observations varies, the variance will vary too. This - violates the "homoschedasticity" assumption, necessary for interpreting the :math:`R^2` as - variance explained. - 2. The :math:`R^2` capture the variance explained when the relationship between the observations and - the predictors is linear. In GLMs, the link function sets a non-linear mapping between the predictors - and the mean of the observations, compromising the interpretation of the :math:`R^2`. + Ignoring the relation between them can result in underestimating the model + performance; for instance, when we model a Poisson variable with large mean we expect an + equally large variance. In this scenario, even if our model perfectly captures the mean, + the high-variance will result in large residuals and low :math:`R^2`. + Additionally, when the mean of the observations varies, the variance will vary too. This + violates the "homoschedasticity" assumption, necessary for interpreting the :math:`R^2` as + variance explained. + + 2. The :math:`R^2` capture the variance explained when the relationship between the observations and + the predictors is linear. In GLMs, the link function sets a non-linear mapping between the predictors + and the mean of the observations, compromising the interpretation of the :math:`R^2`. Note that it is possible to re-normalized the residuals by a mean-dependent quantity proportional to the model standard deviation (i.e. Pearson residuals). This "rescaled" residual distribution however @@ -778,9 +779,9 @@ def simulate( ------- simulated_activity : Simulated activity (spike counts for Poisson GLMs) for the neuron over time. - Shape: (n_time_bins, ). + Shape: ``(n_time_bins, )``. firing_rates : - Simulated rates for the neuron over time. Shape, (n_time_bins, ). + Simulated rates for the neuron over time. Shape, ``(n_time_bins, )``. Raises ------ @@ -916,14 +917,18 @@ def initialize_params( Raises ------ ValueError - - If ``params`` is not of length two. - - If dimensionality of ``init_params`` are not correct. - - If ``X`` is not two-dimensional. - - If ``y`` is not correct (1D for GLM, 2D for populationGLM). + If ``params`` is not of length two. + ValueError + If dimensionality of ``init_params`` are not correct. + ValueError + If ``X`` is not two-dimensional. + ValueError + If ``y`` is not correct (1D for GLM, 2D for populationGLM). TypeError - - If ``params`` are not array-like when provided. - - If ``init_params[i]`` cannot be converted to jnp.ndarray for all i + If ``params`` are not array-like when provided. + TypeError + If ``init_params[i]`` cannot be converted to jnp.ndarray for all i Examples -------- @@ -1004,7 +1009,7 @@ def initialize_state( ) self.regularizer.mask = jnp.ones((1, data.shape[1])) - opt_solver_kwargs = self.optimize_solver_params(data, y) + opt_solver_kwargs = self._optimize_solver_params(data, y) # set up the solver init/run/update attrs self.instantiate_solver(solver_kwargs=opt_solver_kwargs) @@ -1105,7 +1110,7 @@ def update( return opt_step - def get_optimal_solver_params_config(self): + def _get_optimal_solver_params_config(self): """Return the functions for computing default step and batch size for the solver.""" return glm_compute_optimal_stepsize_configs(self) @@ -1137,8 +1142,8 @@ class PopulationGLM(GLM): **Fitting Large Models** For very large models, you may consider using the Stochastic Variance Reduced Gradient - ([SVRG](../solvers/_svrg/#nemos.solvers._svrg.SVRG)) or its proximal variant - ([ProxSVRG](../solvers/_svrg/#nemos.solvers._svrg.ProxSVRG)) solver, + :class:`nemos.solvers._svrg.SVRG` or its proximal variant + (:class:`nemos.solvers._svrg.ProxSVRG`) solver, which take advantage of batched computation. You can change the solver by passing ``"SVRG"`` or ``"ProxSVRG"`` as ``solver_name`` at model initialization. @@ -1274,7 +1279,7 @@ def __init__( @property def feature_mask(self) -> Union[jnp.ndarray, dict]: - """Define a feature mask of shape (n_features, n_neurons).""" + """Define a feature mask of shape ``(n_features, n_neurons)``.""" return self._feature_mask @feature_mask.setter diff --git a/tests/test_base_class.py b/tests/test_base_class.py index 2324434b..95680638 100644 --- a/tests/test_base_class.py +++ b/tests/test_base_class.py @@ -24,7 +24,7 @@ def predict(self, X: Union[NDArray, jnp.ndarray]) -> jnp.ndarray: def score(self, X, y, score_type="pseudo-r2-McFadden"): pass - def get_optimal_solver_params_config(self): + def _get_optimal_solver_params_config(self): return None, None, None diff --git a/tests/test_glm.py b/tests/test_glm.py index d49bb69b..9cdb38eb 100644 --- a/tests/test_glm.py +++ b/tests/test_glm.py @@ -1962,7 +1962,7 @@ def test_optimize_solver_params( raise e return - kwargs = model.optimize_solver_params(X, y) + kwargs = model._optimize_solver_params(X, y) if isinstance(batch_size, int) and "batch_size" in solver_kwargs: # if batch size was provided, then it should be returned unchanged assert batch_size == kwargs["batch_size"] @@ -2049,7 +2049,7 @@ def test_optimize_solver_params_pytree( raise e return - kwargs = model.optimize_solver_params(X, y) + kwargs = model._optimize_solver_params(X, y) if isinstance(batch_size, int) and "batch_size" in solver_kwargs: # if batch size was provided, then it should be returned unchanged assert batch_size == kwargs["batch_size"] @@ -4057,7 +4057,7 @@ def test_optimize_solver_params( raise e return - kwargs = model.optimize_solver_params(X, y) + kwargs = model._optimize_solver_params(X, y) if isinstance(batch_size, int) and "batch_size" in solver_kwargs: # if batch size was provided, then it should be returned unchanged assert batch_size == kwargs["batch_size"] @@ -4144,7 +4144,7 @@ def test_optimize_solver_params_pytree( raise e return - kwargs = model.optimize_solver_params(X, y) + kwargs = model._optimize_solver_params(X, y) if isinstance(batch_size, int) and "batch_size" in solver_kwargs: # if batch size was provided, then it should be returned unchanged assert batch_size == kwargs["batch_size"] From 7404c3029385ef17daa8970e2213fcc40ec52ae3 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Tue, 12 Nov 2024 16:13:00 -0500 Subject: [PATCH 013/107] improved docstrings --- docs/conf.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index f4e35720..2c63d8c7 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -105,10 +105,11 @@ napoleon_use_param = True napoleon_use_rtype = True -autodoc_typehints = "description" # Use "description" to place hints in the description +autodoc_typehints = "none" # Use "description" to place hints in the description autodoc_type_aliases = { "ArrayLike": "ArrayLike", - "NDArray": "NDArray" + "NDArray": "NDArray", + "TsdFrame": "pynapple.TsdFrame", } numfig = True From 8cb592cee588fb6a26202fbc668a7c4f9c603d3d Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Wed, 13 Nov 2024 11:21:13 -0500 Subject: [PATCH 014/107] edited more docstrings --- src/nemos/basis.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/nemos/basis.py b/src/nemos/basis.py index f829d018..0df1a5f9 100644 --- a/src/nemos/basis.py +++ b/src/nemos/basis.py @@ -610,7 +610,7 @@ def _check_convolution_kwargs(self): @property def n_output_features(self) -> int | None: """ - Read-only property indicating the number of features returned by the basis, when available. + Number of features returned by the basis. Notes ----- @@ -622,16 +622,22 @@ def n_output_features(self) -> int | None: @property def label(self) -> str: + """Label for the basis.""" return self._label @property def n_basis_input(self) -> tuple | None: + """Number of expected inputs. + + The number of inputs `compute_feature expects. + """ if self._n_basis_input is None: return return self._n_basis_input @property def n_basis_funcs(self): + """Number of basis functions.""" return self._n_basis_funcs @n_basis_funcs.setter @@ -646,6 +652,7 @@ def n_basis_funcs(self, value): @property def bounds(self): + """Range of values covered by the basis.""" return self._bounds @bounds.setter @@ -672,10 +679,15 @@ def bounds(self, values: Union[None, Tuple[float, float]]): @property def mode(self): + """Mode of operation, either ``"conv"`` or ``"eval"``.""" return self._mode @property def window_size(self): + """Window size as number of samples. + + Duration of the convolutional kernel in number of samples. + """ return self._window_size @window_size.setter @@ -1945,6 +1957,10 @@ def __init__( @property def order(self): + """Spline order. + + Spline order, i.e. the polynomial degree of the spline plus one. + """ return self._order @order.setter @@ -2969,7 +2985,11 @@ def __init__( @property def decay_rates(self): - """Decay rate getter.""" + """Decay rate. + + The rate of decay of the exponential functions. If :math:`f_i(t) = \exp{-\alpha_i t}` is the i-th decay + exponential before orthogonalization, :math:`\alpha_i` is the i-th element of the ``decay_rate`` vector. + """ return self._decay_rates @decay_rates.setter From b839d4f42cb86bd77fa3675f2ee440c9ed0d4ed7 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Wed, 13 Nov 2024 12:30:58 -0500 Subject: [PATCH 015/107] edited docstrings for observation models --- docs/api_guide.rst | 13 ++ src/nemos/observation_models.py | 212 ++++++++++++++++---------------- 2 files changed, 118 insertions(+), 107 deletions(-) diff --git a/docs/api_guide.rst b/docs/api_guide.rst index c06e04e7..cc41a97e 100644 --- a/docs/api_guide.rst +++ b/docs/api_guide.rst @@ -35,3 +35,16 @@ The ``nemos.basis`` module AdditiveBasis MultiplicativeBasis TransformerBasis + +The ``nemos.observation_models`` module +-------------------------------------- + +.. currentmodule:: nemos.observation_models + +.. autosummary:: + :toctree: generated/observation_models + :recursive: + :nosignatures: + + PoissonObservations + GammaObservations \ No newline at end of file diff --git a/src/nemos/observation_models.py b/src/nemos/observation_models.py index 9d683ae1..1c650db2 100644 --- a/src/nemos/observation_models.py +++ b/src/nemos/observation_models.py @@ -10,7 +10,7 @@ from . import utils from .base_class import Base -__all__ = ["PoissonObservations"] +__all__ = ["PoissonObservations", "GammaObservations"] def __dir__(): @@ -72,6 +72,7 @@ def check_inverse_link_function(inverse_link_function: Callable): Check if the provided inverse_link_function is usable. This function verifies if the inverse link function: + 1. Is callable 2. Returns a jax.numpy.ndarray 3. Is differentiable (via jax) @@ -210,9 +211,9 @@ def deviance( Parameters ---------- spike_counts: - The spike counts. Shape (n_time_bins, ) or (n_time_bins, n_neurons) for population models. + The spike counts. Shape ``(n_time_bins, )`` or ``(n_time_bins, n_neurons)`` for population models. predicted_rate: - The predicted firing rates. Shape (n_time_bins, ) or (n_time_bins, n_neurons) for population models. + The predicted firing rates. Shape ``(n_time_bins, )`` or ``(n_time_bins, n_neurons)`` for population models. scale: Scale parameter of the model. @@ -232,17 +233,16 @@ def estimate_scale( ) -> Union[float, jnp.ndarray]: r"""Estimate the scale parameter for the model. - This method estimates the scale parameter, often denoted as $\phi$, which determines the dispersion + This method estimates the scale parameter, often denoted as :math:`\phi`, which determines the dispersion of an exponential family distribution. The probability density function (pdf) for such a distribution is generally expressed as - $f(x; \theta, \phi) \propto \exp \left(a(\phi)\left( y\theta - \mathcal{k}(\theta) \right)\right)$. + :math:`f(x; \theta, \phi) \propto \exp \left(a(\phi)\left( y\theta - \mathcal{k}(\theta) \right)\right)`. The relationship between variance and the scale parameter is given by: - $$ - \text{var}(Y) = \frac{V(\mu)}{a(\phi)}. - $$ + .. math:: + \text{var}(Y) = \frac{V(\mu)}{a(\phi)}. - The scale parameter, $\phi$, is necessary for capturing the variance of the data accurately. + The scale parameter, :math:`\phi`, is necessary for capturing the variance of the data accurately. Parameters ---------- @@ -265,61 +265,64 @@ def pseudo_r2( scale: Union[float, jnp.ndarray, NDArray] = 1.0, aggregate_sample_scores: Callable = jnp.mean, ) -> jnp.ndarray: - r"""Pseudo-$R^2$ calculation for a GLM. + r"""Pseudo-:math:`R^2` calculation for a GLM. - Compute the pseudo-$R^2$ metric for the GLM, as defined by McFadden et al.[$^{[1]}$](#references) - or by Cohen et al.[$^{[2]}$](#references). + Compute the pseudo-:math:`R^2` metric for the GLM, as defined by McFadden et al. [1]_ + or by Cohen et al. [2]_. This metric evaluates the goodness-of-fit of the model relative to a null (baseline) model that assumes a - constant mean for the observations. While the pseudo-$R^2$ is bounded between 0 and 1 for the training set, + constant mean for the observations. While the pseudo-:math:`R^2` is bounded between 0 and 1 for the training set, it can yield negative values on out-of-sample data, indicating potential over-fitting. Parameters ---------- y: - The neural activity. Expected shape: (n_time_bins, ) + The neural activity. Expected shape: ``(n_time_bins, )`` predicted_rate: - The mean neural activity. Expected shape: (n_time_bins, ) + The mean neural activity. Expected shape: ``(n_time_bins, )`` score_type: - The pseudo-R$^2$ type. + The pseudo-:math:`R^2` type. scale: The scale parameter of the model. Returns ------- : - The pseudo-$R^2$ of the model. A value closer to 1 indicates a better model fit, + The pseudo-:math:`R^2` of the model. A value closer to 1 indicates a better model fit, whereas a value closer to 0 suggests that the model doesn't improve much over the null model. Notes ----- - - The McFadden pseudo-$R^2$ is given by: - $$ + - The McFadden pseudo-:math:`R^2` is given by: + + .. math:: R^2_{\text{mcf}} = 1 - \frac{\log(L_{M})}{\log(L_0)}. - $$ - *Equivalent to statsmodels - [`GLMResults.pseudo_rsquared(kind='mcf')`](https://www.statsmodels.org/dev/generated/statsmodels.genmod.generalized_linear_model.GLMResults.pseudo_rsquared.html).* - - The Cohen pseudo-$R^2$ is given by: - $$ + + *Equivalent to statsmodels* + `GLMResults.pseudo_rsquared(kind='mcf') `_ . + + - The Cohen pseudo-:math:`R^2` is given by: + + .. math:: \begin{aligned} R^2_{\text{Cohen}} &= \frac{D_0 - D_M}{D_0} \\\ &= 1 - \frac{\log(L_s) - \log(L_M)}{\log(L_s)-\log(L_0)}, \end{aligned} - $$ - where $L_M$, $L_0$ and $L_s$ are the likelihood of the fitted model, the null model (a - model with only the intercept term), and the saturated model (a model with one parameter per - sample, i.e. the maximum value that the likelihood could possibly achieve). $D_M$ and $D_0$ are - the model and the null deviance, $D_i = -2 \left[ \log(L_s) - \log(L_i) \right]$ for $i=M,0$. - - # References - ------------ - [1] McFadden D (1979). Quantitative methods for analysing travel behavior of individuals: Some recent - developments. In D. A. Hensher & P. R. Stopher (Eds.), *Behavioural travel modelling* (pp. 279-318). - London: Croom Helm. - - [2] Jacob Cohen, Patricia Cohen, Steven G. West, Leona S. Aiken. - *Applied Multiple Regression/Correlation Analysis for the Behavioral Sciences*. - 3rd edition. Routledge, 2002. p.502. ISBN 978-0-8058-2223-6. (May 2012) + + where :math:`L_M`, :math:`L_0` and :math:`L_s` are the likelihood of the fitted model, the null model (a + model with only the intercept term), and the saturated model (a model with one parameter per + sample, i.e. the maximum value that the likelihood could possibly achieve). :math:`D_M` and :math:`D_0` are + the model and the null deviance, :math:`D_i = -2 \left[ \log(L_s) - \log(L_i) \right]` for :math:`i=M,0`. + + References + ---------- + .. [1] McFadden D (1979). Quantitative methods for analysing travel behavior of individuals: Some recent + developments. In D. A. Hensher & P. R. Stopher (Eds.), *Behavioural travel modelling* (pp. 279-318). + London: Croom Helm. + + .. [2] Jacob Cohen, Patricia Cohen, Steven G. West, Leona S. Aiken. + *Applied Multiple Regression/Correlation Analysis for the Behavioral Sciences*. + 3rd edition. Routledge, 2002. p.502. ISBN 978-0-8058-2223-6. (May 2012) """ if score_type == "pseudo-r2-McFadden": pseudo_r2 = self._pseudo_r2_mcfadden( @@ -342,22 +345,22 @@ def _pseudo_r2_cohen( predicted_rate: jnp.ndarray, aggregate_sample_scores: Callable = jnp.mean, ) -> jnp.ndarray: - r"""Cohen's pseudo-$R^2$. + r"""Cohen's pseudo-:math:`R^2`. - Compute the pseudo-$R^2$ metric as defined by Cohen et al. (2002). See - [`pseudo_r2`](#pseudo_r2) for additional information. + Compute the pseudo-:math:`R^2` metric as defined by Cohen et al. (2002). See + :meth:`nemos.observation_models.Observations.pseudo_r2` for additional information. Parameters ---------- y: - The neural activity. Expected shape: (n_time_bins, ) + The neural activity. Expected shape: ``(n_time_bins, )``. predicted_rate: - The mean neural activity. Expected shape: (n_time_bins, ) + The mean neural activity. Expected shape: ``(n_time_bins, )`` Returns ------- : - The pseudo-$R^2$ of the model. A value closer to 1 indicates a better model fit, + The pseudo-:math:`R^2` of the model. A value closer to 1 indicates a better model fit, whereas a value closer to 0 suggests that the model doesn't improve much over the null model. """ model_dev_t = self.deviance(y, predicted_rate) @@ -376,10 +379,10 @@ def _pseudo_r2_mcfadden( aggregate_sample_scores: Callable = jnp.mean, ): """ - McFadden's pseudo-$R^2$. + McFadden's pseudo-:math:`R^2`. - Compute the pseudo-$R^2$ metric as defined by McFadden et al. (1979). See - [`pseudo_r2`](#pseudo_r2) for additional information. + Compute the pseudo-:math:`R^2` metric as defined by McFadden et al. (1979). See + :meth:`nemos.observation_models.Observations.pseudo_r2` for additional information. Parameters ---------- @@ -393,7 +396,7 @@ def _pseudo_r2_mcfadden( Returns ------- : - The pseudo-$R^2$ of the model. A value closer to 1 indicates a better model fit, + The pseudo-:math:`R^2` of the model. A value closer to 1 indicates a better model fit, whereas a value closer to 0 suggests that the model doesn't improve much over the null model. """ mean_y = jnp.ones(y.shape) * y.mean(axis=0) @@ -420,11 +423,7 @@ class PoissonObservations(Observations): Attributes ---------- inverse_link_function : - A function that maps the predicted rate to the domain of the Poisson parameter. Defaults to jnp.exp. - - See Also - -------- - [Observations](./#nemos.observation_models.Observations) : Base class for observation models. + A function that maps the predicted rate to the domain of the Poisson parameter. Defaults to ``jax.numpy.exp``. """ @@ -459,7 +458,7 @@ def _negative_log_likelihood( ----- The formula for the Poisson mean log-likelihood is the following, - $$ + .. math:: \begin{aligned} \text{LL}(\hat{\lambda} | y) &= \frac{1}{T \cdot N} \sum_{n=1}^{N} \sum_{t=1}^{T} [y\_{tn} \log(\hat{\lambda}\_{tn}) - \hat{\lambda}\_{tn} - \log({y\_{tn}!})] \\\ @@ -468,11 +467,10 @@ def _negative_log_likelihood( &= \frac{1}{T \cdot N} \sum_{n=1}^{N} \sum_{t=1}^{T} [y\_{tn} \log(\hat{\lambda}\_{tn}) - \hat{\lambda}\_{tn}] + \\text{const} \end{aligned} - $$ - Because $\Gamma(k+1)=k!$, see [wikipedia](https://en.wikipedia.org/wiki/Gamma_function) for explanation. + Because :math:`\Gamma(k+1)=k!`, see `wikipedia ` for explanation. - The $\log({y\_{tn}!})$ term is not a function of the parameters and can be disregarded + The :math:`\log({y\_{tn}!})` term is not a function of the parameters and can be disregarded when computing the loss-function. This is why we incorporated it into the `const` term. """ predicted_rate = jnp.clip( @@ -497,9 +495,9 @@ def log_likelihood( Parameters ---------- y : - The target spikes to compare against. Shape (n_time_bins, ), or (n_time_bins, n_neurons). + The target spikes to compare against. Shape ``(n_time_bins, )``, or ``(n_time_bins, n_neurons)``. predicted_rate : - The predicted rate of the current model. Shape (n_time_bins, ), or (n_time_bins, n_neurons). + The predicted rate of the current model. Shape ``(n_time_bins, )``, or ``(n_time_bins, n_neurons)``. scale : The scale parameter of the model. aggregate_sample_scores : @@ -514,20 +512,20 @@ def log_likelihood( ----- The formula for the Poisson mean log-likelihood is the following, - $$ - \begin{aligned} - \text{LL}(\hat{\lambda} | y) &= \frac{1}{T \cdot N} \sum_{n=1}^{N} \sum_{t=1}^{T} - [y\_{tn} \log(\hat{\lambda}\_{tn}) - \hat{\lambda}\_{tn} - \log({y\_{tn}!})] \\\ - &= \frac{1}{T \cdot N} \sum_{n=1}^{N} \sum_{t=1}^{T} [y\_{tn} \log(\hat{\lambda}\_{tn}) - - \hat{\lambda}\_{tn} - \Gamma({y\_{tn}+1})] \\\ - &= \frac{1}{T \cdot N} \sum_{n=1}^{N} \sum_{t=1}^{T} [y\_{tn} \log(\hat{\lambda}\_{tn}) - - \hat{\lambda}\_{tn}] + \\text{const} - \end{aligned} - $$ + .. math:: + \begin{aligned} + \text{LL}(\hat{\lambda} | y) &= \frac{1}{T \cdot N} \sum_{n=1}^{N} \sum_{t=1}^{T} + [y_{tn} \log(\hat{\lambda}_{tn}) - \hat{\lambda}_{tn} - \log({y_{tn}!})] \\\ + &= \frac{1}{T \cdot N} \sum_{n=1}^{N} \sum_{t=1}^{T} [y_{tn} \log(\hat{\lambda}_{tn}) - + \hat{\lambda}_{tn} - \Gamma({y_{tn}+1})] \\\ + &= \frac{1}{T \cdot N} \sum_{n=1}^{N} \sum_{t=1}^{T} [y_{tn} \log(\hat{\lambda}_{tn}) - + \hat{\lambda}_{tn}] + \text{const} + \end{aligned} - Because $\Gamma(k+1)=k!$, see [wikipedia](https://en.wikipedia.org/wiki/Gamma_function) for explanation. - The $\log({y\_{tn}!})$ term is not a function of the parameters and can be disregarded + Because :math:`\Gamma(k+1)=k!`, see `wikipedia `_ for explanation. + + The :math:`\log({y_{tn}!})` term is not a function of the parameters and can be disregarded when computing the loss-function. This is why we incorporated it into the `const` term. """ nll = self._negative_log_likelihood(y, predicted_rate, aggregate_sample_scores) @@ -550,7 +548,8 @@ def sample_generator( key : Random key used for the generation of random numbers in JAX. predicted_rate : - Expected rate (lambda) of the Poisson distribution. Shape (n_time_bins, ), or (n_time_bins, n_neurons). + Expected rate (lambda) of the Poisson distribution. Shape ``(n_time_bins, )``, or + ``(n_time_bins, n_neurons)``. scale : Scale parameter. For Poisson should be equal to 1. @@ -572,9 +571,10 @@ def deviance( Parameters ---------- spike_counts: - The spike counts. Shape (n_time_bins, ) or (n_time_bins, n_neurons) for population models. + The spike counts. Shape ``(n_time_bins, )`` or ``(n_time_bins, n_neurons)`` for population models. predicted_rate: - The predicted firing rates. Shape (n_time_bins, ) or (n_time_bins, n_neurons) for population models. + The predicted firing rates. Shape ``(n_time_bins, )`` or ``(n_time_bins, n_neurons)`` for + population models. scale: Scale parameter of the model. @@ -588,16 +588,15 @@ def deviance( The deviance is a measure of the goodness of fit of a statistical model. For a Poisson model, the residual deviance is computed as: - $$ - \begin{aligned} - D(y\_{tn}, \hat{y}\_{tn}) &= 2 \left[ y\_{tn} \log\left(\frac{y\_{tn}}{\hat{y}\_{tn}}\right) - - (y\_{tn} - \hat{y}\_{tn}) \right]\\\ - &= 2 \left( \text{LL}\left(y\_{tn} | y\_{tn}\right) - \text{LL}\left(y\_{tn} | \hat{y}\_{tn}\right)\right) - \end{aligned} - $$ + .. math:: + \begin{aligned} + D(y_{tn}, \hat{y}_{tn}) &= 2 \left[ y_{tn} \log\left(\frac{y_{tn}}{\hat{y}_{tn}}\right) + - (y_{tn} - \hat{y}_{tn}) \right]\\\ + &= 2 \left( \text{LL}\left(y_{tn} | y_{tn}\right) - \text{LL}\left(y_{tn} | \hat{y}_{tn}\right)\right) + \end{aligned} - where $ y $ is the observed data, $ \hat{y} $ is the predicted data, and $\text{LL}$ is the model - log-likelihood. Lower values of deviance indicate a better fit. + where :math:`y` is the observed data, :math:`\hat{y}` is the predicted data, and :math:`\text{LL}` is + the model log-likelihood. Lower values of deviance indicate a better fit. """ # this takes care of 0s in the log ratio = jnp.clip( @@ -615,13 +614,15 @@ def estimate_scale( r""" Assign 1 to the scale parameter of the Poisson model. - For the Poisson exponential family distribution, the scale parameter $\phi$ is always 1. + For the Poisson exponential family distribution, the scale parameter :math:`\phi` is always 1. This property is consistent with the fact that the variance equals the mean in a Poisson distribution. As given in the general exponential family expression: - $$ - \text{var}(Y) = \frac{V(\mu)}{a(\phi)}, - $$ - for the Poisson family, it simplifies to $\text{var}(Y) = \mu$ since $a(\phi) = 1$ and $V(\mu) = \mu$. + + .. math:: + \text{var}(Y) = \frac{V(\mu)}{a(\phi)}, + + for the Poisson family, it simplifies to :math:`\text{var}(Y) = \mu` since :math:`a(\phi) = 1` + and :math:`V(\mu) = \mu`. Parameters ---------- @@ -649,10 +650,6 @@ class GammaObservations(Observations): inverse_link_function : A function that maps the predicted rate to the domain of the Poisson parameter. Defaults to jnp.exp. - See Also - -------- - [Observations](./#nemos.observation_models.Observations) : Base class for observation models. - """ def __init__(self, inverse_link_function=lambda x: jnp.power(x, -1)): @@ -786,16 +783,16 @@ def deviance( The deviance is a measure of the goodness of fit of a statistical model. For a Gamma model, the residual deviance is computed as: - $$ - \begin{aligned} - D(y\_{tn}, \hat{y}\_{tn}) &= 2 \left[ -\log \frac{ y\_{tn}}{\hat{y}\_{tn}} + \frac{y\_{tn} - - \hat{y}\_{tn}}{\hat{y}\_{tn}}\right]\\\ - &= 2 \left( \text{LL}\left(y\_{tn} | y\_{tn}\right) - \text{LL}\left(y\_{tn} | \hat{y}\_{tn}\right) \right) - \end{aligned} - $$ + .. math:: + \begin{aligned} + D(y_{tn}, \hat{y}_{tn}) &= 2 \left[ -\log \frac{ y_{tn}}{\hat{y}_{tn}} + \frac{y_{tn} - + \hat{y}_{tn}}{\hat{y}_{tn}}\right]\\\ + &= 2 \left( \text{LL}\left(y_{tn} | y_{tn}\right) - \text{LL}\left(y_{tn} | \hat{y}_{tn}\right) \right) + \end{aligned} - where $ y $ is the observed data, $ \hat{y} $ is the predicted data, and $\text{LL}$ is the model + where :math:`y` is the observed data, :math:`\hat{y}` is the predicted data, and :math:`\text{LL}` is the model log-likelihood. Lower values of deviance indicate a better fit. + """ y_mu = jnp.clip(neural_activity / predicted_rate, min=jnp.finfo(float).eps) resid_dev = 2 * ( @@ -812,11 +809,12 @@ def estimate_scale( r""" Estimate the scale of the model based on the GLM residuals. - For $y \sim \Gamma$ the scale is equal to, - $$ - \Phi = \frac{\text{Var(y)}}{V(\mu)} - $$ - with $V(\mu) = \mu^2$. + For :math:`y \sim \Gamma` the scale is equal to, + + .. math:: + \Phi = \frac{\text{Var(y)}}{V(\mu)} + + with :math:`V(\mu) = \mu^2`. Therefore, the scale can be estimated as the ratio of the sample variance to the squared rate. @@ -833,7 +831,7 @@ def estimate_scale( Returns ------- : - The scale parameter. If predicted_rate is (n_samples, n_neurons), this method will return a + The scale parameter. If predicted_rate is ``(n_samples, n_neurons)``, this method will return a scale for each neuron. """ predicted_rate = jnp.clip( From 681acf4686fa9ef3553243765cd1cc84befde028 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Wed, 13 Nov 2024 13:58:59 -0500 Subject: [PATCH 016/107] added todos API --- docs/api_guide.rst | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/api_guide.rst b/docs/api_guide.rst index cc41a97e..15251103 100644 --- a/docs/api_guide.rst +++ b/docs/api_guide.rst @@ -47,4 +47,13 @@ The ``nemos.observation_models`` module :nosignatures: PoissonObservations - GammaObservations \ No newline at end of file + GammaObservations + +The ``nemos.regularizer`` module +-------------------------------- + +The ``nemos.simulation`` module +-------------------------------- + +The ``nemos.identifiability_constraints`` module +------------------------------------------------ From 4cbbb1b34b69d88c251f0ace61b62ab29a3ad1d3 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 14 Nov 2024 15:35:24 -0500 Subject: [PATCH 017/107] set docstrings for simulation --- docs/api_guide.rst | 23 +++++++ src/nemos/regularizer.py | 72 +++++++++------------ src/nemos/simulation.py | 132 +++++++++++++++++++++++++++++++-------- 3 files changed, 157 insertions(+), 70 deletions(-) diff --git a/docs/api_guide.rst b/docs/api_guide.rst index 15251103..873ef701 100644 --- a/docs/api_guide.rst +++ b/docs/api_guide.rst @@ -52,8 +52,31 @@ The ``nemos.observation_models`` module The ``nemos.regularizer`` module -------------------------------- +.. currentmodule:: nemos.regularizer + +.. autosummary:: + :toctree: generated/regularizer + :recursive: + :nosignatures: + + UnRegularized + Ridge + Lasso + GroupLasso + The ``nemos.simulation`` module -------------------------------- +.. currentmodule:: nemos.simulation + +.. autosummary:: + :toctree: generated/regularizer + :recursive: + :nosignatures: + + simulate_recurrent + difference_of_gammas + regress_filter + The ``nemos.identifiability_constraints`` module ------------------------------------------------ diff --git a/src/nemos/regularizer.py b/src/nemos/regularizer.py index 6d6cf0bd..f26913f4 100644 --- a/src/nemos/regularizer.py +++ b/src/nemos/regularizer.py @@ -96,24 +96,11 @@ def get_proximal_operator( class UnRegularized(Regularizer): """ - Solver class for optimizing unregularized models. + Regularizer class for unregularized models. - This class provides an interface to various optimization methods for models that - do not involve regularization. The optimization methods that are allowed for this - class are defined in the `allowed_solvers` attribute. - - Attributes - ---------- - allowed_solvers : list of str - List of solver names that are allowed for this regularizer class. - default_solver : - Default solver for this regularizer is GradientDescent. - - See Also - -------- - [Regularizer](./#nemos.regularizer.Regularizer) : Base solver class from which this class inherits. + This class equips models with the identity proximal operator (no shrinkage) and the + unpenalized loss function. """ - _allowed_solvers = ( "GradientDescent", "BFGS", @@ -133,32 +120,31 @@ def __init__( def penalized_loss(self, loss: Callable, regularizer_strength: float): """ - Returns the original loss function unpenalized. Unregularized regularization method does not add any - penalty. + Returns the original loss function unpenalized. + + Unregularized regularization method does not add any penalty. """ return loss def get_proximal_operator( self, ) -> ProximalOperator: - """Unregularized method has no proximal operator.""" + """ + Returns the identity operator. + + Unregularized method corresponds to an identity proximal operator, since no + shrinkage factor is applied. + """ return jaxopt.prox.prox_none class Ridge(Regularizer): """ - Solver for Ridge regularization using various optimization algorithms. - - This class uses `jaxopt` optimizers to perform Ridge regularization. It extends - the base Solver class, with the added feature of Ridge penalization. + Regularizer class for Ridge (L2 regularization). - Attributes - ---------- - allowed_solvers : List[..., str] - A list of solver names that are allowed to be used with this regularizer. - default_solver : - Default solver for this regularizer is GradientDescent. + This class equips models with the Ridge proximal operator and the + Ridge penalized loss function. """ _allowed_solvers = ( @@ -240,12 +226,13 @@ def prox_op(params, l2reg, scaling=1.0): class Lasso(Regularizer): """ - Optimization solver using the Lasso (L1 regularization) method with Proximal Gradient. + Regularizer class for Lasso (L1 regularization). - This class is a specialized version of the ProxGradientSolver with the proximal operator - set for L1 regularization (Lasso). It utilizes the `jaxopt` library's proximal gradient optimizer. + This class equips models with the lasso proximal operator and the + lasso penalized loss function. """ + _allowed_solvers = ( "ProximalGradient", "ProxSVRG", @@ -318,33 +305,30 @@ def _penalized_loss(params, X, y): class GroupLasso(Regularizer): """ - Optimization solver using the Group Lasso regularization method with Proximal Gradient. + Regularizer class for Group Lasso (group-L1) regularized models. - This class is a specialized version of the ProxGradientSolver with the proximal operator - set for Group Lasso regularization. The Group Lasso regularization induces sparsity on groups - of features rather than individual features. + This class equips models with the group-lasso proximal operator and the + group-lasso penalized loss function. Attributes ---------- mask : - A 2d mask array indicating groups of features for regularization, shape (num_groups, num_features). + A 2d mask array indicating groups of features for regularization, shape ``(num_groups, num_features)``. Each row represents a group of features. Each column corresponds to a feature, where a value of 1 indicates that the feature belongs to the group, and a value of 0 indicates it doesn't. - Default is `mask = np.ones((1, num_features))`, grouping all features in a single group. + Default is ``mask = np.ones((1, num_features))``, grouping all features in a single group. Examples -------- >>> import numpy as np >>> from nemos.regularizer import GroupLasso # Assuming the module is named group_lasso >>> from nemos.glm import GLM - >>> # simulate some counts >>> num_samples, num_features, num_groups = 1000, 5, 3 >>> X = np.random.normal(size=(num_samples, num_features)) # design matrix >>> w = [0, 0.5, 1, 0, -0.5] # define some weights >>> y = np.random.poisson(np.exp(X.dot(w))) # observed counts - >>> # Define a mask for 3 groups and 5 features >>> mask = np.zeros((num_groups, num_features)) >>> mask[0] = [1, 0, 0, 1, 0] # Group 0 includes features 0 and 3 @@ -439,12 +423,14 @@ def _penalization( Note: the penalty is being calculated according to the following formula: - $$\\text{loss}(\beta_1,...,\beta_g) + \alpha \cdot \sum _{j=1...,g} \sqrt{\dim(\beta_j)} || \beta_j||_2$$ + .. math:: - where $g$ is the number of groups, $\dim(\cdot)$ is the dimension of the vector, - i.e. the number of coefficient in each $\beta_j$, and $||\cdot||_2$ is the euclidean norm. + \\text{loss}(\beta_1,...,\beta_g) + \alpha \cdot \sum _{j=1...,g} \sqrt{\dim(\beta_j)} || \beta_j||_2 + where :math:`g` is the number of groups, :math:`\dim(\cdot)` is the dimension of the vector, + i.e. the number of coefficient in each :math:`\beta_j`, and :math:`||\cdot||_2` is the euclidean norm. """ + # conform to shape (1, n_features) if param is (n_features,) or (n_neurons, n_features) if # param is (n_features, n_neurons) param_with_extra_axis = jnp.atleast_2d(params[0].T) diff --git a/src/nemos/simulation.py b/src/nemos/simulation.py index e698e702..c62d5c8c 100644 --- a/src/nemos/simulation.py +++ b/src/nemos/simulation.py @@ -20,7 +20,8 @@ def difference_of_gammas( inhib_b: float = 1.0, excit_b: float = 2.0, ) -> NDArray: - r"""Generate coupling filter as a Gamma pdf difference. + r""" + Generate coupling filter as a Gamma pdf difference. Parameters ---------- @@ -30,22 +31,24 @@ def difference_of_gammas( Upper bound of the gamma range as a percentile. The gamma function will be evaluated over the range [0, ppf(upper_percentile)]. inhib_a: - The `a` constant for the gamma pdf of the inhibitory part of the filter. + The ``a`` constant for the gamma pdf of the inhibitory part of the filter. excit_a: - The `a` constant for the gamma pdf of the excitatory part of the filter. + The ``a`` constant for the gamma pdf of the excitatory part of the filter. inhib_b: - The `b` constant for the gamma pdf of the inhibitory part of the filter. + The ``b`` constant for the gamma pdf of the inhibitory part of the filter. excit_b: - The `a` constant for the gamma pdf of the excitatory part of the filter. + The ``a`` constant for the gamma pdf of the excitatory part of the filter. Notes ----- The probability density function of a gamma distribution is parametrized as - follows[$^{[1]}$](#references):, - $$ + follows [1]_ :, + + .. math:: + p(x;\; a, b) = \frac{b^a x^{a-1} e^{-x}}{\Gamma(a)}, - $$ - where $\Gamma(a)$ refers to the gamma function, see [[1]](#references):. + + where :math:`\Gamma(a)` refers to the gamma function, see [[1]](#references). Returns ------- @@ -58,9 +61,28 @@ def difference_of_gammas( - If any of the Gamma parameters is lesser or equal to 0. - If the upper_percentile is not in [0, 1). - # References - ------------ - SciPy Docs - ["scipy.stats.gamma"](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.gamma.html) + References + ---------- + SciPy Docs - :meth:`scipy.stats.gamma ` + + Examples + -------- + >>> import matplotlib.pyplot as plt + >>> from nemos.simulation import difference_of_gammas + >>> coupling_duration = 100 + >>> inhib_a, inhib_b = 1.0, 1.0 + >>> excit_a, excit_b = 2.0, 2.0 + >>> coupling_filter = difference_of_gammas( + ... ws=coupling_duration, + ... inhib_a=inhib_a, + ... inhib_b=inhib_b, + ... excit_a=excit_a, + ... excit_b=excit_b + ... ) + >>> _ = plt.plot(coupling_filter) + >>> _ = plt.title("Coupling filter from difference of gammas") + >>> _ = plt.show() + """ # check that the gamma parameters are positive (scipy returns # nans otherwise but no exception is raised) @@ -102,21 +124,42 @@ def regress_filter(coupling_filters: NDArray, eval_basis: NDArray) -> NDArray: Parameters ---------- coupling_filters: - The coupling filters. Shape (window_size, n_neurons_receiver, n_neurons_sender) + The coupling filters. Shape ``(window_size, n_neurons_receiver, n_neurons_sender)`` eval_basis: - The evaluated basis function, shape (window_size, n_basis_funcs) + The evaluated basis function, shape ``(window_size, n_basis_funcs)`` Returns ------- weights: - The weights for each neuron. Shape (n_neurons_receiver, n_neurons_sender, n_basis_funcs) + The weights for each neuron. Shape ``(n_basis_funcs, n_neurons_receiver, n_neurons_sender)`` Raises ------ ValueError - - If eval_basis is not two-dimensional - - If coupling_filters is not three-dimensional - - If window_size differs between eval_basis and coupling_filters + If eval_basis is not two-dimensional. + ValueError + If coupling_filters is not three-dimensional. + ValueError + If window_size differs between eval_basis and coupling_filters. + + Examples + -------- + >>> import numpy as np + >>> import matplotlib.pyplot as plt + >>> from nemos.simulation import regress_filter, difference_of_gammas + >>> from nemos.basis import RaisedCosineBasisLog + >>> filter_duration = 100 + >>> n_basis_funcs = 20 + >>> filter_bank = difference_of_gammas(filter_duration).reshape(filter_duration, 1, 1) + >>> _, basis = RaisedCosineBasisLog(10).evaluate_on_grid(filter_duration) + >>> weights = regress_filter(filter_bank, basis)[0, 0] + >>> print("Weights shape:", weights.shape) + >>> _ = plt.plot(filter_bank[:, 0, 0], label=f"True filter") + >>> _ = plt.plot(basis.dot(weights), "--", label=f"Approx. filter") + >>> _ = plt.legend() + >>> _ = plt.title("True vs. Approximated Filters") + >>> _ = plt.show() + """ # check shapes if eval_basis.ndim != 2: @@ -182,37 +225,72 @@ def simulate_recurrent( Expected shape: (n_neurons (receiver), n_neurons (sender), n_basis_coupling). feedforward_coef : Coefficients for the feedforward inputs to each neuron. - Expected shape: (n_neurons, n_basis_input). + Expected shape: ``(n_neurons, n_basis_input)``. intercepts : - Bias term for each neuron. Expected shape: (n_neurons,). + Bias term for each neuron. Expected shape: ``(n_neurons,)``. random_key : jax.random.key for seeding the simulation. feedforward_input : External input matrix to the model, representing factors like convolved currents, light intensities, etc. When not provided, the simulation is done with coupling-only. - Expected shape: (n_time_bins, n_neurons, n_basis_input). + Expected shape: ``(n_time_bins, n_neurons, n_basis_input)``. init_y : Initial observation (spike counts for PoissonGLM) matrix that kickstarts the simulation. - Expected shape: (window_size, n_neurons). + Expected shape: ``(window_size, n_neurons)``. coupling_basis_matrix : Basis matrix for coupling, representing between-neuron couplings - and auto-correlations. Expected shape: (window_size, n_basis_coupling). + and auto-correlations. Expected shape: ``(window_size, n_basis_coupling)``. + inverse_link_function : + The inverse link function for the observation model. Returns ------- simulated_activity : Simulated activity (spike counts for PoissonGLMs) for each neuron over time. - Shape, (n_time_bins, n_neurons). + Shape, ``(n_time_bins, n_neurons)``. firing_rates : - Simulated rates for each neuron over time. Shape, (n_time_bins, n_neurons,). + Simulated rates for each neuron over time. Shape, ``(n_time_bins, n_neurons,)``. Raises ------ ValueError - - If there's an inconsistency between the number of neurons in model parameters. - - If the number of neurons in input arguments doesn't match with model parameters. + If there's an inconsistency between the number of neurons in model parameters. + ValueError + If the number of neurons in input arguments doesn't match with model parameters. + + Examples + -------- + >>> import numpy as np + >>> import jax + >>> import matplotlib.pyplot as plt + >>> from nemos.simulation import simulate_recurrent + >>> + >>> n_neurons = 2 + >>> coupling_duration = 100 + >>> feedforward_input = np.random.normal(size=(1000, n_neurons, 1)) + >>> coupling_basis = np.random.normal(size=(coupling_duration, 10)) + >>> coupling_coef = np.random.normal(size=(n_neurons, n_neurons, 10)) + >>> intercept = -8 * np.ones(n_neurons) + >>> init_spikes = np.zeros((coupling_duration, n_neurons)) + >>> random_key = jax.random.key(123) + >>> spikes, rates = simulate_recurrent( + ... coupling_coef=coupling_coef, + ... feedforward_coef=np.ones((n_neurons, 1)), + ... intercepts=intercept, + ... random_key=random_key, + ... feedforward_input=feedforward_input, + ... coupling_basis_matrix=coupling_basis, + ... init_y=init_spikes + ... ) + >>> _ = plt.figure() + >>> _ = plt.plot(rates[:, 0], label="Neuron 0 rate") + >>> _ = plt.plot(rates[:, 1], label="Neuron 1 rate") + >>> _ = plt.legend() + >>> _ = plt.title("Simulated firing rates") + >>> _ = plt.show() """ + if isinstance(feedforward_input, FeaturePytree): raise ValueError( "simulate_recurrent works only with arrays. " From 50ffcbd75ec521724e79af844b8cc1ccf21521cd Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 14 Nov 2024 16:03:13 -0500 Subject: [PATCH 018/107] finished docstrings parsing --- docs/api_guide.rst | 19 ++++++++++++++++++- docs/conf.py | 3 ++- src/nemos/identifiability_constraints.py | 8 ++++---- src/nemos/regularizer.py | 4 ++-- 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/docs/api_guide.rst b/docs/api_guide.rst index 873ef701..34a7e364 100644 --- a/docs/api_guide.rst +++ b/docs/api_guide.rst @@ -5,6 +5,7 @@ API Guide The ``nemos.glm`` module ------------------------ +Classes for creating Generalized Linear Models (GLMs) for both single neurons and neural populations. .. currentmodule:: nemos.glm @@ -18,6 +19,7 @@ The ``nemos.glm`` module The ``nemos.basis`` module -------------------------- +Provides basis function classes to construct and transform features for model inputs. .. currentmodule:: nemos.basis @@ -38,6 +40,7 @@ The ``nemos.basis`` module The ``nemos.observation_models`` module -------------------------------------- +Statistical models to describe the distribution of neural responses or other predicted variables, given inputs. .. currentmodule:: nemos.observation_models @@ -51,6 +54,7 @@ The ``nemos.observation_models`` module The ``nemos.regularizer`` module -------------------------------- +Implements various regularization techniques to constrain model parameters, which helps prevent overfitting. .. currentmodule:: nemos.regularizer @@ -65,7 +69,8 @@ The ``nemos.regularizer`` module GroupLasso The ``nemos.simulation`` module --------------------------------- +------------------------------- +Utility functions for simulating spiking activity in recurrently connected neural populations. .. currentmodule:: nemos.simulation @@ -80,3 +85,15 @@ The ``nemos.simulation`` module The ``nemos.identifiability_constraints`` module ------------------------------------------------ +Functions to apply identifiability constraints to rank-deficient feature matrices, ensuring the uniqueness of model +solutions. + +.. currentmodule:: nemos.identifiability_constraints + +.. autosummary:: + :toctree: generated/identifiability_constraints + :recursive: + :nosignatures: + + apply_identifiability_constraints + apply_identifiability_constraints_by_basis_component diff --git a/docs/conf.py b/docs/conf.py index 2c63d8c7..50da5b79 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -105,11 +105,12 @@ napoleon_use_param = True napoleon_use_rtype = True -autodoc_typehints = "none" # Use "description" to place hints in the description +autodoc_typehints = "description" # Use "description" to place hints in the description autodoc_type_aliases = { "ArrayLike": "ArrayLike", "NDArray": "NDArray", "TsdFrame": "pynapple.TsdFrame", + "JaxArray": "JaxArray", } numfig = True diff --git a/src/nemos/identifiability_constraints.py b/src/nemos/identifiability_constraints.py index 79437c65..0ab515a9 100644 --- a/src/nemos/identifiability_constraints.py +++ b/src/nemos/identifiability_constraints.py @@ -180,9 +180,9 @@ def apply_identifiability_constraints( warn_if_float32: bool = True, ) -> Tuple[NDArray, NDArray[int]]: """ - Apply identifiability constraints to a design matrix `X`. + Apply identifiability constraints to a design matrix ``X``. - Removes columns from `X` until it is full rank to ensure the uniqueness + Removes columns from ``X`` until it is full rank to ensure the uniqueness of the GLM (Generalized Linear Model) maximum-likelihood solution. This is particularly crucial for models using bases like BSplines and CyclicBspline, which, due to their construction, sum to 1 and can cause rank deficiency when combined with an intercept. @@ -192,7 +192,7 @@ def apply_identifiability_constraints( in the absence of regularization. For very large feature matrices generated by a sum of low-dimensional basis components, consider - `apply_identifiability_constraints_by_basis_component`. + ``apply_identifiability_constraints_by_basis_component``. Parameters ---------- @@ -261,7 +261,7 @@ def apply_identifiability_constraints_by_basis_component( Parameters ---------- basis: - The basis that computed X. + The basis that computed ``feature_matrix``. feature_matrix: The feature matrix before applying the identifiability constraints. add_intercept: diff --git a/src/nemos/regularizer.py b/src/nemos/regularizer.py index f26913f4..3cc1f3eb 100644 --- a/src/nemos/regularizer.py +++ b/src/nemos/regularizer.py @@ -228,8 +228,8 @@ class Lasso(Regularizer): """ Regularizer class for Lasso (L1 regularization). - This class equips models with the lasso proximal operator and the - lasso penalized loss function. + This class equips models with the Lasso proximal operator and the + Lasso penalized loss function. """ From c936e9b30fb50318a7d18b43341778235e74e9f9 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 14 Nov 2024 16:25:19 -0500 Subject: [PATCH 019/107] added MD files converted with jupytext --- docs/background/plot_00_conceptual_intro.md | 228 ++++++ docs/background/plot_01_1D_basis_function.md | 194 +++++ docs/background/plot_02_ND_basis_function.md | 342 ++++++++ docs/background/plot_03_1D_convolution.md | 169 ++++ docs/conf.py | 1 - docs/how_to_guide/plot_02_glm_demo.md | 412 ++++++++++ docs/how_to_guide/plot_03_glm_pytree.md | 354 +++++++++ docs/how_to_guide/plot_04_population_glm.md | 219 ++++++ docs/how_to_guide/plot_05_batch_glm.md | 243 ++++++ .../plot_06_sklearn_pipeline_cv_demo.md | 552 +++++++++++++ docs/index.md | 6 - docs/tutorials/plot_01_current_injection.md | 730 ++++++++++++++++++ docs/tutorials/plot_02_head_direction.md | 671 ++++++++++++++++ docs/tutorials/plot_03_grid_cells.md | 305 ++++++++ docs/tutorials/plot_04_v1_cells.md | 334 ++++++++ docs/tutorials/plot_05_place_cells.md | 489 ++++++++++++ docs/tutorials/plot_06_calcium_imaging.md | 339 ++++++++ src/nemos/identifiability_constraints.py | 2 +- 18 files changed, 5582 insertions(+), 8 deletions(-) create mode 100644 docs/background/plot_00_conceptual_intro.md create mode 100644 docs/background/plot_01_1D_basis_function.md create mode 100644 docs/background/plot_02_ND_basis_function.md create mode 100644 docs/background/plot_03_1D_convolution.md create mode 100644 docs/how_to_guide/plot_02_glm_demo.md create mode 100644 docs/how_to_guide/plot_03_glm_pytree.md create mode 100644 docs/how_to_guide/plot_04_population_glm.md create mode 100644 docs/how_to_guide/plot_05_batch_glm.md create mode 100644 docs/how_to_guide/plot_06_sklearn_pipeline_cv_demo.md create mode 100644 docs/tutorials/plot_01_current_injection.md create mode 100644 docs/tutorials/plot_02_head_direction.md create mode 100644 docs/tutorials/plot_03_grid_cells.md create mode 100644 docs/tutorials/plot_04_v1_cells.md create mode 100644 docs/tutorials/plot_05_place_cells.md create mode 100644 docs/tutorials/plot_06_calcium_imaging.md diff --git a/docs/background/plot_00_conceptual_intro.md b/docs/background/plot_00_conceptual_intro.md new file mode 100644 index 00000000..7b9cf602 --- /dev/null +++ b/docs/background/plot_00_conceptual_intro.md @@ -0,0 +1,228 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +```{code-cell} ipython3 +%matplotlib inline +``` + +# Generalized Linear Models: An Introduction + +Before we dive into using NeMoS, you might wonder: why model at all? Why not + just make a bunch of tuning curves and submit to *Science*? Modeling is + helpful because: + +- The tuning curve reflects the correlation between neuronal spiking and + feature of interest, but activity might be driven by some other highly + correlated input (after all, [correlation does not imply + causation](https://xkcd.com/552/)). How do you identify what's driving + activity? + +- Your model instantiates specific hypotheses about the system (e.g., that + only instantaneous current matters for firing rate) and makes specific + quantitative predictions that can be used to compare among hypotheses. + +!!! warning + + We are not claiming that the GLM will allow you to uniquely determine + causation! Like any statistical model or method, the GLM will not solve + causation for you (causation being a notoriously difficult problem in + science), but it will allow you to see the effect of adding and removing + different inputs on the predicted firing rate, which can facilitate + causal inferences. For more reading on causation and explanation in + neuroscience, the work of [Carl + Craver](https://philosophy.wustl.edu/people/carl-f-craver) is a good + place to start. + +Now that we've convinced you that modeling is worthwhile, let's get started! +How should we begin? + +When modeling, it's generally a good idea to start simple and add complexity +as needed. Simple models are: + +- Easier to understand, so you can more easily reason through why a model is + capturing or not capturing some feature of your data. + +- Easier to fit, so you can more quickly see how you did. + +- Surprisingly powerful, so you might not actually need all the bells and + whistles you expected. + +Therefore, let's start with the simplest possible model: the only input is the +instantaneous value of some input. This is equivalent to saying that the only +input influencing the firing rate of this neuron at time $t$ is the input it +received at that same time. As neuroscientists, we know this isn't true, but +given the data exploration we did above, it looks like a reasonable starting +place. We can always build in more complications later. + +### GLM components + +The Generalized Linear Model in neuroscience can also be thought of as a LNP +model: a linear-nonlinear-Poisson model. + +
+ +Linear-Non Linear-Poisson illustration. +
LNP model schematic. Modified from Pillow et al., 2008.
+
+ +The model receives some input and then: + +- sends it through a linear filter or transformation of some sort. +- passes that through a nonlinearity to get the *firing rate*. +- uses the firing rate as the mean of a Poisson process to generate *spikes*. + +Let's step through each of those in turn. + +Our input feature(s) are first passed through a linear transformation, which +rescales and shifts the input: $\bm{WX}+\bm{c}$. In the one-dimensional case, as +in this example, this is equivalent to scaling it by a constant and adding an +intercept. + +!!! note + + In geometry, this is more correctly referred to as an [affine + transformation](https://en.wikipedia.org/wiki/Affine_transformation), + which includes translations, scaling, and rotations. *Linear* + transformations are the subset of affine transformations that do not + include translations. + + In neuroscience, "linear" is the more common term, and we will use it + throughout. + +This means that, in the 1d case, we have two knobs to transform the input: we +can make it bigger or smaller, or we can shift it up or down. That is, we +compute: + +$$L(x(t)) = w x(t) + c \tag{1}$$ + +for some value of $w$ and $c$. Let's visualize some possible transformations +that our model can make with three cartoon neurons: + +```{code-cell} ipython3 +import matplotlib.pyplot as plt + +# first import things +import numpy as np +import pynapple as nap + +import nemos as nmo + +# some helper plotting functions +from nemos import _documentation_utils as doc_plots + +# configure plots some +plt.style.use(nmo.styles.plot_style) +``` + +to simplify things, we will look at three simple LNP neuron models as +described above, working through each step of the transform. First, we will +plot the linear transformation of the input x: + + +```{code-cell} ipython3 +weights = np.asarray([.5, 4, -4]) +intercepts = np.asarray([.5, -3, -2]) + +# make a step function with some noise riding on top +input_feature = np.zeros(100) +input_feature[50:] = 1 +input_feature *= np.random.rand(100) +input_feature = nap.Tsd(np.linspace(0, 100, 100), input_feature) + +fig = doc_plots.lnp_schematic(input_feature, weights, intercepts) +``` + +With these linear transformations, we see that we can stretch or shrink the +input and move its baseline up or down. Remember that the goal of this +model is to predict the firing rate of the neuron. Thus, changing what +happens when there's zero input is equivalent to changing the baseline firing +rate of the neuron, so that's how we should think about the intercept. + +However, if this is meant to be the firing rate, there's something odd --- +the output of the linear transformation is often negative, but firing rates +have to be non-negative! That's what the nonlinearity handles: making sure our +firing rate is always positive. We can visualize this second stage of the LNP model +by adding the `plot_nonlinear` keyword to our `lnp_schematic()` plotting function: + + +```{code-cell} ipython3 +fig = doc_plots.lnp_schematic(input_feature, weights, intercepts, + plot_nonlinear=True) +``` + +!!! info + + In NeMoS, the non-linearity is kept fixed. We default to the exponential, + but a small number of other choices, such as soft-plus, are allowed. The + allowed choices guarantee both the non-negativity constraint described + above, as well as convexity, i.e. a single optimal solution. In + principle, one could choose a more complex non-linearity, but convexity + is not guaranteed in general. + +Specifically, our firing rate is: +$$ \lambda (t) = \exp (L(x(t)) = \exp (w x(t) + c) \tag{2}$$ + +We can see that the output of the nonlinear transformation is always +positive, though note that the y-values have changed drastically. + +Now we're ready to look at the third step of the LNP model, and see what +the generated spikes spikes look like! + + +```{code-cell} ipython3 +# mkdocs_gallery_thumbnail_number = 3 +fig = doc_plots.lnp_schematic(input_feature, weights, intercepts, + plot_nonlinear=True, plot_spikes=True) +``` + +Remember, spiking is a stochastic process. That means that a given firing +rate can give rise to a variety of different spike trains; the plot above +shows three possibilities for each neuron. Each spike train is a sample from +a Poisson process with the mean equal to the firing rate, i.e., output of +the linear-nonlinear parts of the model. + +Given that this is a stochastic process that could produce an infinite number +of possible spike trains, how do we compare our model against the single +observed spike train we have? We use the _log-likelihood_. This quantifies how +likely it is to observe the given spike train for the computed firing rate: +if $y(t)$ is the spike counts and $\lambda(t)$ the firing rate, the equation +for the log-likelihood is + +$$ \sum\_t \log P(y(t) | \lambda(t)) = \sum\_t y(t) \log(\lambda(t)) - +\lambda(t) - \log (y(t)!)\tag{3}$$ + +Note that this last $\log(y(t)!)$ term does not depend on $\lambda(t)$ and +thus is independent of the model, so it is normally ignored. + +$$ \sum\_t \log P(y(t) | \lambda(t)) \propto \sum\_t y(t) \log(\lambda(t)) - +\lambda(t))\tag{4}$$ + +This is the objective function of the GLM model: we are trying to find the +firing rate that maximizes the likelihood of the observed spike train. + +!!! info + + In NeMoS, the log-likelihood can be computed directly by calling the + `score` method, passing the predictors and the counts. The method first + computes the rate $\lambda(t)$ using (2) and then the likelihood using + (4). This method is used under the hood during optimization. + + ++++ + +## More general GLMs +So far, we have focused on the relatively simple LNP model of spike generation, which is a special case of a GLM. The LNP model has some known shortcomings[$^{[1]}$](#ref-1). For instance, LNP ignores things like refactory periods and other history-dependent features of spiking in a neuron. As we will show in other demos, such _spike history filters_ can be built into GLMs to give more accurate results. We will also show how, if you have recordings from a large _population_ of neurons simultaneously, you can build connections between the neurons into the GLM in the form of _coupling filters_. This can help answer the degree to which activity is driven primarily by the input X, or by network influences in the population. + +## References + +[1]
Pillow, JW, Shlens, J, Paninski, L, Sher, A, Litke, AM, Chichilnisky, EJ, Simoncelli, EP (2008), "Spatio-temporal correlations and visual signalling in a complete neuronal population." Nature 454: 995-9. diff --git a/docs/background/plot_01_1D_basis_function.md b/docs/background/plot_01_1D_basis_function.md new file mode 100644 index 00000000..f4063f2d --- /dev/null +++ b/docs/background/plot_01_1D_basis_function.md @@ -0,0 +1,194 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +```{code-cell} ipython3 +%matplotlib inline +``` + + +# One-Dimensional Basis + +## Defining a 1D Basis Object + +We'll start by defining a 1D basis function object of the type `MSplineBasis`. +The hyperparameters required to initialize this class are: + +- The number of basis functions, which should be a positive integer. +- The order of the spline, which should be an integer greater than 1. + +```{code-cell} ipython3 +import matplotlib.pylab as plt +import numpy as np +import pynapple as nap + +import nemos as nmo + +# Initialize hyperparameters +order = 4 +n_basis = 10 + +# Define the 1D basis function object +bspline = nmo.basis.BSplineBasis(n_basis_funcs=n_basis, order=order) +``` + +## Evaluating a Basis + +The `Basis` object is callable, and can be evaluated as a function. By default, the support of the basis +is defined by the samples that we input to the `__call__` method, and covers from the smallest to the largest value. + + +```{code-cell} ipython3 +# Generate a time series of sample points +samples = nap.Tsd(t=np.arange(1001), d=np.linspace(0, 1,1001)) + +# Evaluate the basis at the sample points +eval_basis = bspline(samples) + +# Output information about the evaluated basis +print(f"Evaluated B-spline of order {order} with {eval_basis.shape[1]} " + f"basis element and {eval_basis.shape[0]} samples.") + +plt.figure() +plt.title("B-spline basis") +plt.plot(eval_basis) +``` + +## Setting the basis support +Sometimes, it is useful to restrict the basis to a fixed range. This can help manage outliers or ensure that +your basis covers the same range across multiple experimental sessions. +You can specify a range for the support of your basis by setting the `bounds` +parameter at initialization. Evaluating the basis at any sample outside the bounds will result in a NaN. + + +```{code-cell} ipython3 +bspline_range = nmo.basis.BSplineBasis(n_basis_funcs=n_basis, order=order, bounds=(0.2, 0.8)) + +print("Evaluated basis:") +# 0.5 is within the support, 0.1 is outside the support +print(np.round(bspline_range([0.5, 0.1]), 3)) +``` + +Let's compare the default behavior of basis (estimating the range from the samples) with +the fixed range basis. + + +```{code-cell} ipython3 +fig, axs = plt.subplots(2,1, sharex=True) +plt.suptitle("B-spline basis ") +axs[0].plot(bspline(samples), color="k") +axs[0].set_title("default") +axs[1].plot(bspline_range(samples), color="tomato") +axs[1].set_title("bounds=[0.2, 0.8]") +plt.tight_layout() +``` + +## Basis `mode` +In constructing features, `Basis` objects can be used in two modalities: `"eval"` for evaluate or `"conv"` +for convolve. These two modalities change the behavior of the `construct_features` method of `Basis`, in particular, + +- If a basis is in mode `"eval"`, then `construct_features` simply returns the evaluated basis. +- If a basis is in mode `"conv"`, then `construct_features` will convolve the input with a kernel of basis + with `window_size` specified by the user. + +Let's see how this two modalities operate. + + +```{code-cell} ipython3 +eval_mode = nmo.basis.MSplineBasis(n_basis_funcs=n_basis, mode="eval") +conv_mode = nmo.basis.MSplineBasis(n_basis_funcs=n_basis, mode="conv", window_size=100) + +# define an input +angles = np.linspace(0, np.pi*4, 201) +y = np.cos(angles) + +# compute features in the two modalities +eval_feature = eval_mode.compute_features(y) +conv_feature = conv_mode.compute_features(y) + +# plot results +fig, axs = plt.subplots( 3, 1, sharex="all", figsize=(6, 4)) + +# plot signal +axs[0].set_title("Input") +axs[0].plot(y) +axs[0].set_xticks([]) +axs[0].set_ylabel("signal", fontsize=12) + +# plot eval results +axs[1].set_title("eval features") +axs[1].imshow(eval_feature.T, aspect="auto") +axs[1].set_xticks([]) +axs[1].set_ylabel("basis", fontsize=12) + +# plot conv results +axs[2].set_title("convolutional features") +axs[2].imshow(conv_feature.T, aspect="auto") +axs[2].set_xlabel("time", fontsize=12) +axs[2].set_ylabel("basis", fontsize=12) +plt.tight_layout() +``` + +!!! note "NaN-Padding" + Convolution is performed in "valid" mode, and then NaN-padded. The default behavior + is padding left, which makes the output feature causal. + This is why the first half of the `conv_feature` is full of NaNs and appears as white. + If you want to learn more about convolutions, as well as how and when to change defaults + check out the tutorial on [1D convolutions](../plot_03_1D_convolution). + + ++++ + +Plotting the Basis Function Elements: +-------------------------------------- +We suggest visualizing the basis post-instantiation by evaluating each element on a set of equi-spaced sample points +and then plotting the result. The method `Basis.evaluate_on_grid` is designed for this, as it generates and returns +the equi-spaced samples along with the evaluated basis functions. The benefits of using Basis.evaluate_on_grid become +particularly evident when working with multidimensional basis functions. You can find more details and visual +background in the +[2D basis elements plotting section](../plot_02_ND_basis_function/#plotting-2d-additive-basis-elements). + + +```{code-cell} ipython3 +# Call evaluate on grid on 100 sample points to generate samples and evaluate the basis at those samples +n_samples = 100 +equispaced_samples, eval_basis = bspline.evaluate_on_grid(n_samples) + +# Plot each basis element +plt.figure() +plt.title(f"B-spline basis with {eval_basis.shape[1]} elements\nevaluated at {eval_basis.shape[0]} sample points") +plt.plot(equispaced_samples, eval_basis) +plt.show() +``` + +Other Basis Types +----------------- +Each basis type may necessitate specific hyperparameters for instantiation. For a comprehensive description, +please refer to the [API Guide](../../../reference/nemos/basis). After instantiation, all classes +share the same syntax for basis evaluation. The following is an example of how to instantiate and +evaluate a log-spaced cosine raised function basis. + + +```{code-cell} ipython3 +# Instantiate the basis noting that the `RaisedCosineBasisLog` does not require an `order` parameter +raised_cosine_log = nmo.basis.RaisedCosineBasisLog(n_basis_funcs=10, width=1.5, time_scaling=50) + +# Evaluate the raised cosine basis at the equi-spaced sample points +# (same method in all Basis elements) +samples, eval_basis = raised_cosine_log.evaluate_on_grid(100) + +# Plot the evaluated log-spaced raised cosine basis +plt.figure() +plt.title(f"Log-spaced Raised Cosine basis with {eval_basis.shape[1]} elements") +plt.plot(samples, eval_basis) +plt.show() +``` diff --git a/docs/background/plot_02_ND_basis_function.md b/docs/background/plot_02_ND_basis_function.md new file mode 100644 index 00000000..e0e47776 --- /dev/null +++ b/docs/background/plot_02_ND_basis_function.md @@ -0,0 +1,342 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +```{code-cell} ipython3 +%matplotlib inline +``` + + +# Multidimensional Basis + +## Background + +In many cases, it's necessary to model the response of a neuron to multiple different inputs +(such as velocity, spatial position, LFP phase, etc.). Such response functions can often be expressed as a linear +combination of some multidimensional basis elements. + +In this document, we introduce two strategies for defining a high-dimensional basis function by combining +two lower-dimensional bases. We refer to these strategies as "addition" and "multiplication" of bases, +and the resulting basis objects will be referred to as additive or multiplicative basis respectively. + + +Consider we have two inputs $\mathbf{x} \in \mathbb{R}^N,\; \mathbf{y}\in \mathbb{R}^M$. +Let's say we've defined two basis functions for these inputs: + +- $ [ a_0 (\mathbf{x}), ..., a_{k-1} (\mathbf{x}) ] $ for $\mathbf{x}$ +- $[b_0 (\mathbf{y}), ..., b_{h-1} (\mathbf{y}) ]$ for $\mathbf{y}$. + +These basis functions can be combined in the following ways: + +1. **Addition:** If we assume that there is no interaction between the stimuli, the response function can be adequately described by the sum of the individual components. The function is defined as: + $$ + f(\mathbf{x}, \mathbf{y}) \\approx \sum_{i=0}^{k-1} \\alpha_{i} \, a_i (\mathbf{x}) + \sum_{j=0}^{h-1} \\beta_j b_j(\mathbf{y}). + $$ + The resulting additive basis simply consists of the concatenation of the two basis sets: $$[A_0 (\mathbf{x}, \mathbf{y}), ..., A_{k+h-1} (\mathbf{x}, \mathbf{y})],$$ where + $$ + A_j(\mathbf{x}, \mathbf{y}) = \\begin{cases} a_j(\mathbf{x}) & \\text{if }\; j \leq k-1 \\\\\ b_{j-k+1}(\mathbf{y}) & \\text{otherwise.} \end{cases} + $$ + Note that we have a total of $k+h$ basis elements, and that each element is constant in one of the axis. + +2. **Multiplication:** If we expect the response function to capture arbitrary interactions between the inputs, we can approximate it as the external product of the two bases: + $$ + f(\mathbf{x}, \mathbf{y}) \\approx \sum_{i=0}^{k-1}\sum_{j=0}^{h-1} \\alpha_{ij} \, a_i (\mathbf{x}) b_j(\mathbf{y}). + $$ + In this case, the resulting basis consists of the $h \cdot k$ products of the individual bases: $$[A_0(\mathbf{x}, \mathbf{y}),..., A_{k \cdot h-1}(\mathbf{x}, \mathbf{y})],$$ + where, + $$ + A_{i \cdot h + j}(\mathbf{x}, \mathbf{y}) = a_i(\mathbf{x})b_{j}(\mathbf{y}), \; \\text{for} \; i=0,\dots, k-1 \; \\text{ and } \; j=0,\dots,h-1. + $$ + +In the subsequent sections, we will: + +1. Demonstrate the definition, evaluation, and visualization of 2D additive and multiplicative bases. +2. Illustrate how to iteratively apply addition and multiplication operations to extend to dimensions beyond two. + +## 2D Basis Functions + +Consider an instance where we want to capture a neuron's response to an animal's position within a given arena. +In this scenario, the stimuli are the 2D coordinates (x, y) that represent the animal's position at each time point. + ++++ + +### Additive Basis Object +One way to model the response to our 2D stimuli is to hypothesize that it decomposes into two factors: +one due to the x-coordinate and another due to the y-coordinate. We can express this relationship as: +$$ +f(x,y) \\approx \sum_i \alpha_i \cdot a_i(x) + \sum_j \beta_j \cdot b_j(y). +$$ +Here, we simply add two basis objects, `a_basis` and `b_basis`, together to define the additive basis. + + +```{code-cell} ipython3 +import matplotlib.pyplot as plt +import numpy as np + +import nemos as nmo + +# Define 1D basis objects +a_basis = nmo.basis.MSplineBasis(n_basis_funcs=15, order=3) +b_basis = nmo.basis.RaisedCosineBasisLog(n_basis_funcs=14) + +# Define the 2D additive basis object +additive_basis = a_basis + b_basis +``` + +Evaluating the additive basis will require two inputs, one for each coordinate. +The total number of elements of the additive basis will be the sum of the elements of the 1D basis. + + +```{code-cell} ipython3 +# Define a trajectory with 1000 time-points representing the recorded trajectory of the animal +T = 1000 + +# Define two variables +x_coord = np.linspace(0, 1, 1000) +y_coord = np.linspace(0, 1, 1000) + +# Evaluate the basis functions for the given trajectory. +eval_basis = additive_basis(x_coord, y_coord) + +print(f"Sum of two 1D splines with {eval_basis.shape[1]} " + f"basis element and {eval_basis.shape[0]} samples:\n" + f"\t- a_basis had {a_basis.n_basis_funcs} elements\n\t- b_basis had {b_basis.n_basis_funcs} elements.") +``` + +#### Plotting 2D Additive Basis Elements +Let's select and plot a basis element from each of the basis we added. + + +```{code-cell} ipython3 +basis_a_element = 5 +basis_b_element = 1 +# Plot the 1D basis elements +fig, axs = plt.subplots(1, 2, figsize=(6, 3)) + +axs[0].set_title(f"$a_{{{basis_a_element}}}(x)$", color="b") +axs[0].plot(x_coord, a_basis(x_coord), "grey", alpha=.3) +axs[0].plot(x_coord, a_basis(x_coord)[:, basis_a_element], "b") +axs[0].set_xlabel("x-coord") + +axs[1].set_title(f"$b_{{{basis_b_element}}}(x)$", color="b") +axs[1].plot(y_coord, b_basis(x_coord), "grey", alpha=.3) +axs[1].plot(y_coord, b_basis(x_coord)[:, basis_b_element], "b") +axs[1].set_xlabel("y-coord") +plt.tight_layout() +``` + +We can visualize how these elements are extended in 2D by evaluating the additive basis +on a grid of points that spans its domain and plotting the result. +We use the `evaluate_on_grid` method for this. + + +```{code-cell} ipython3 +X, Y, Z = additive_basis.evaluate_on_grid(200, 200) +``` + +We can select the indices of the 2D additive basis that corresponds to the 1D original elements. + + +```{code-cell} ipython3 +basis_elem_idx = [basis_a_element, a_basis.n_basis_funcs + basis_b_element] +``` + +Finally, we can plot the 2D counterparts. + + +```{code-cell} ipython3 +_, axs = plt.subplots(1, 2, subplot_kw={'aspect': 1}) + +# Plot the corresponding 2D elements. +# As expected, each element will be constant on one of the axis. +axs[0].set_title(f"$A_{{{basis_elem_idx[0]}}}(x,y) = " + f"a_{{{basis_a_element}}}(x)$", color="b") + +axs[1].set_title(f"$A_{{{basis_elem_idx[1]}}}(x,y) = " + f"b_{{{basis_b_element}}}(x)$", color="b") + +for cc in range(len(basis_elem_idx)): + axs[cc].contourf(X, Y, Z[..., basis_elem_idx[cc]], cmap="Blues") + axs[cc].set_xlabel("x-coord") + axs[cc].set_ylabel("y-coord") +plt.tight_layout() +plt.show() +``` + +### Multiplicative Basis Object + +If the aim is to capture interactions between the coordinates, the response function can be modeled as the external +product of two 1D basis functions. The approximation of the response function in this scenario would be: + +$$ +f(x, y) \\approx \sum_{ij} \\alpha_{ij} \, a_i (x) b_j(y). +$$ + +In this model, we define the 2D basis function as the product of two 1D basis objects. +This allows the response to capture non-linear and interaction effects between the x and y coordinates. + + +```{code-cell} ipython3 +# 2D basis function as the product of the two 1D basis objects +prod_basis = a_basis * b_basis +``` + +Again evaluating the basis will require 2 inputs. +The number of elements of the product basis will be the product of the elements of the two 1D bases. + + +```{code-cell} ipython3 +# Evaluate the product basis at the x and y coordinates +eval_basis = prod_basis(x_coord, y_coord) + +# Output the number of elements and samples of the evaluated basis, +# as well as the number of elements in the original 1D basis objects +print(f"Product of two 1D splines with {eval_basis.shape[1]} " + f"basis element and {eval_basis.shape[0]} samples:\n" + f"\t- a_basis had {a_basis.n_basis_funcs} elements\n\t- b_basis had {b_basis.n_basis_funcs} elements.") +``` + +#### Plotting 2D Multiplicative Basis Elements +Plotting works in the same way as before. To demonstrate that, we select a few pairs of 1D basis elements, +and we visualize the corresponding product. + + +```{code-cell} ipython3 +# Set this figure as the thumbnail +# mkdocs_gallery_thumbnail_number = 3 + +X, Y, Z = prod_basis.evaluate_on_grid(200, 200) + +# basis element pairs +element_pairs = [[0, 0], [5, 1], [10, 5]] + +# plot the 1D basis element and their product +fig, axs = plt.subplots(3,3,figsize=(8, 6)) +cc = 0 +for i, j in element_pairs: + # plot the element form a_basis + axs[cc, 0].plot(x_coord, a_basis(x_coord), "grey", alpha=.3) + axs[cc, 0].plot(x_coord, a_basis(x_coord)[:, i], "b") + axs[cc, 0].set_title(f"$a_{{{i}}}(x)$",color='b') + + # plot the element form b_basis + axs[cc, 1].plot(y_coord, b_basis(y_coord), "grey", alpha=.3) + axs[cc, 1].plot(y_coord, b_basis(y_coord)[:, j], "b") + axs[cc, 1].set_title(f"$b_{{{j}}}(y)$",color='b') + + # select & plot the corresponding product basis element + k = i * b_basis.n_basis_funcs + j + axs[cc, 2].contourf(X, Y, Z[:, :, k], cmap='Blues') + axs[cc, 2].set_title(f"$A_{{{k}}}(x,y) = a_{{{i}}}(x) \cdot b_{{{j}}}(y)$", color='b') + axs[cc, 2].set_xlabel('x-coord') + axs[cc, 2].set_ylabel('y-coord') + axs[cc, 2].set_aspect("equal") + + cc += 1 +axs[2, 0].set_xlabel('x-coord') +axs[2, 1].set_xlabel('y-coord') + +plt.tight_layout() +``` + +!!! info + Basis objects of different types can be combined through multiplication or addition. + This feature is particularly useful when one of the axes represents a periodic variable and another is non-periodic. + A practical example would be characterizing the responses to position + in a linear maze and the LFP phase angle. + + ++++ + +N-Dimensional Basis +------------------- +Sometimes it may be useful to model even higher dimensional interactions, for example between the heding direction of +an animal and its spatial position. In order to model an N-dimensional response function, you can combine +N 1D basis objects using additions and multiplications. + +!!! warning + If you multiply basis together, the dimension of the evaluated basis function + will increase exponentially with the number of dimensions potentially causing memory errors. + For example, evaluating a product of $N$ 1D bases with $T$ samples and $K$ basis element, + will output a $K^N \times T$ matrix. + + +```{code-cell} ipython3 +T = 10 +n_basis = 8 + +a_basis = nmo.basis.RaisedCosineBasisLinear(n_basis_funcs=n_basis) +b_basis = nmo.basis.RaisedCosineBasisLinear(n_basis_funcs=n_basis) +c_basis = nmo.basis.RaisedCosineBasisLinear(n_basis_funcs=n_basis) + +prod_basis_3 = a_basis * b_basis * c_basis +samples = np.linspace(0, 1, T) +eval_basis = prod_basis_3(samples, samples, samples) + +print(f"Product of three 1D splines results in {prod_basis_3.n_basis_funcs} " + f"basis elements.\nEvaluation output of shape {eval_basis.shape}") +``` + +The evaluation of the product of 3 basis is a 4 dimensional tensor; we can visualize slices of it. + + +```{code-cell} ipython3 +X, Y, W, Z = prod_basis_3.evaluate_on_grid(30, 30, 30) + +# select any slice +slices = [17, 18, 19] +basis_elem_idx = 300 +vmax = Z[:, :, slices, basis_elem_idx].max() +fig, axs = plt.subplots(1, 3, figsize=(8, 3)) +cnt = 0 +for slice_i in slices: + X_slice = X[:, :, slice_i] + Y_slice = Y[:, :, slice_i] + + Z_slice = Z[:, :, slice_i] + axs[cnt].contourf(X_slice, Y_slice, Z_slice[:, :, basis_elem_idx], + cmap='Blues', vmin=0, vmax=vmax) + axs[cnt].set_title(f"Slice {slice_i}") + cnt += 1 + +plt.suptitle(f"Basis element: {basis_elem_idx}") +plt.tight_layout() +plt.show() + +# Check sparsity +print(f"Sparsity check: {(Z == 0).sum() / Z.size * 100: .2f}% of the evaluated basis is null.") +``` + +!!! info + The evaluated basis is going to be **sparse** if the basis elements support do not cover the + full domain of the basis. + + ++++ + +Here we demonstrate a shortcut syntax for multiplying bases of the same class. +This is achieved using the power operator with an integer exponent. + + +```{code-cell} ipython3 +# First, let's define a basis `power_basis` that is equivalent to `prod_basis_3`, +# but we use the power syntax this time: +power_basis = a_basis**3 + +# Now, evaluate the `prod_basis_3` on a 30x30x30 grid and get the last item, let's call it `Z_pow`: +Z_pow_syntax = power_basis.evaluate_on_grid(30, 30, 30)[-1] +Z_prod_syntax = (a_basis * a_basis * a_basis).evaluate_on_grid(30, 30, 30)[-1] + +# We can now assert that the original basis and the new `power_basis` match. +# If they do, the total number of mismatched entries should be zero. +print(f"Total mismatched entries: {(Z_pow_syntax != Z_prod_syntax).sum()}") +``` diff --git a/docs/background/plot_03_1D_convolution.md b/docs/background/plot_03_1D_convolution.md new file mode 100644 index 00000000..5d45b2a7 --- /dev/null +++ b/docs/background/plot_03_1D_convolution.md @@ -0,0 +1,169 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +```{code-cell} ipython3 +%matplotlib inline +``` + + +One-dimensional convolutions + ++++ + +## Generate synthetic data +Generate some simulated spike counts. + + +```{code-cell} ipython3 +import matplotlib.patches as patches +import matplotlib.pylab as plt +import numpy as np + +import nemos as nmo + +np.random.seed(10) +ws = 10 +# samples +n_samples = 100 + +spk = np.random.poisson(lam=0.1, size=(n_samples, )) + +# add borders (extreme case, general border effect are represented) +spk[0] = 1 +spk[3] = 1 +spk[-1] = 1 +spk[-4] = 1 +``` + +## Convolution in `"valid"` mode +Generate and plot a filter, then execute a convolution in "valid" mode for all trials and neurons. + +!!! info + The `"valid"` mode of convolution only calculates the product when the two input vectors overlap completely, + avoiding border artifacts. The outcome of such a convolution will + be an array of `max(M,N) - min(M,N) + 1` elements in length, where `M` and `N` represent the number + of elements in the arrays being convolved. For more detailed information on this, + see [jax.numpy.convolve](https://jax.readthedocs.io/en/latest/_autosummary/jax.numpy.convolve.html). + + +```{code-cell} ipython3 +# create three filters +basis_obj = nmo.basis.RaisedCosineBasisLinear(n_basis_funcs=3) +_, w = basis_obj.evaluate_on_grid(ws) + +plt.plot(w) + +spk_conv = nmo.convolve.reshape_convolve(spk, w) + +# valid convolution should be of shape n_samples - ws + 1 +print(f"Shape of the convolution output: {spk_conv.shape}") +``` + +## Causal, Anti-Causal, and Acausal filters +NaN padding appropriately the output of the convolution allows to model causal, anti-causal and acausal filters. +A causal filter captures how an event or task variable influences the future firing-rate. +An example usage case would be that of characterizing the refractory period of a neuron +(i.e. the drop in firing rate immediately after a spike event). Another example could be characterizing how +the current position of an animal in a maze would affect its future spiking activity. + +On the other hand, if we are interested in capturing the firing rate modulation before an event occurs we may want +to use an anti-causal filter. An example of that may be the preparatory activity of pre-motor cortex that happens +before a movement is initiated (here the event is. "movement onset"). + +Finally, if one wants to capture both causal +and anti-causal effects one should use the acausal filters. +Below we provide a function that runs the convolution in "valid" mode and pads the convolution output +for the different filter types. + + +```{code-cell} ipython3 +# pad according to the causal direction of the filter, after squeeze, +# the dimension is (n_filters, n_samples) +spk_causal_conv = nmo.convolve.create_convolutional_predictor( + w, spk, predictor_causality="causal" +) +spk_anticausal_conv = nmo.convolve.create_convolutional_predictor( + w, spk, predictor_causality="anti-causal" +) +spk_acausal_conv = nmo.convolve.create_convolutional_predictor( + w, spk, predictor_causality="acausal" +) +``` + +Plot the results + + +```{code-cell} ipython3 +# NaN padded area +rect_causal = patches.Rectangle((0, -2.5), ws, 5, alpha=0.3, color='grey') +rect_anticausal = patches.Rectangle((len(spk)-ws, -2.5), ws, 5, alpha=0.3, color='grey') +rect_acausal_left = patches.Rectangle((0, -2.5), (ws-1)//2, 5, alpha=0.3, color='grey') +rect_acausal_right = patches.Rectangle((len(spk) - (ws-1)//2, -2.5), (ws-1)//2, 5, alpha=0.3, color='grey') + +# Set this figure as the thumbnail +# mkdocs_gallery_thumbnail_number = 2 + +plt.figure(figsize=(6, 4)) + +shift_spk = - spk - 0.1 +ax = plt.subplot(311) + +plt.title('valid + nan-pad') +ax.add_patch(rect_causal) +plt.vlines(np.arange(spk.shape[0]), 0, shift_spk, color='k') +plt.plot(np.arange(spk.shape[0]), spk_causal_conv) +plt.ylabel('causal') + +ax = plt.subplot(312) +ax.add_patch(rect_anticausal) +plt.vlines(np.arange(spk.shape[0]), 0, shift_spk, color='k') +plt.plot(np.arange(spk.shape[0]), spk_anticausal_conv) +plt.ylabel('anti-causal') + +ax = plt.subplot(313) +ax.add_patch(rect_acausal_left) +ax.add_patch(rect_acausal_right) +plt.vlines(np.arange(spk.shape[0]), 0, shift_spk, color='k') +plt.plot(np.arange(spk.shape[0]), spk_acausal_conv) +plt.ylabel('acausal') +plt.tight_layout() +``` + +## Convolve using `Basis.compute_features` +All the parameters of `create_convolutional_predictor` can be passed to a `Basis` directly +at initialization. Note that you must set `mode == "conv"` to actually perform convolution +with `Basis.compute_features`. Let's see how we can get the same results through `Basis`. + + +```{code-cell} ipython3 +# define basis with different predictor causality +causal_basis = nmo.basis.RaisedCosineBasisLinear( + n_basis_funcs=3, mode="conv", window_size=ws, + predictor_causality="causal" +) + +acausal_basis = nmo.basis.RaisedCosineBasisLinear( + n_basis_funcs=3, mode="conv", window_size=ws, + predictor_causality="acausal" +) + +anticausal_basis = nmo.basis.RaisedCosineBasisLinear( + n_basis_funcs=3, mode="conv", window_size=ws, + predictor_causality="anti-causal" +) + +# compute convolutions +basis_causal_conv = causal_basis.compute_features(spk) +basis_acausal_conv = acausal_basis.compute_features(spk) +basis_anticausal_conv = anticausal_basis.compute_features(spk) +``` diff --git a/docs/conf.py b/docs/conf.py index 50da5b79..9a0aa79e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -169,5 +169,4 @@ copybutton_prompt_text = r">>> |\$ |# " copybutton_prompt_is_regexp = True - nitpicky = True diff --git a/docs/how_to_guide/plot_02_glm_demo.md b/docs/how_to_guide/plot_02_glm_demo.md new file mode 100644 index 00000000..162ae63f --- /dev/null +++ b/docs/how_to_guide/plot_02_glm_demo.md @@ -0,0 +1,412 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +```{code-cell} ipython3 +%matplotlib inline +``` + + +# GLM Demo: Toy Model Examples + +!!! warning + This demonstration is currently in its alpha stage. It presents various regularization techniques on + GLMs trained on a Gaussian noise stimuli, and a minimal example of fitting and simulating a pair of coupled + neurons. More work needs to be done to properly compare the performance of the regularization strategies on + realistic simulations and real neural recordings. + +## Introduction + +In this demo we will work through two toy examples of a Poisson-GLM on synthetic data: a purely feed-forward input model +and a recurrently coupled model. + +In particular, we will learn how to: + +- Define & configurate a GLM object. +- Fit the model +- Cross-validate the model with `sklearn` +- Simulate spike trains. + +Before digging into the GLM module, let's first import the packages + we are going to use for this tutorial, and generate some synthetic + data. + +```{code-cell} ipython3 +import jax +import matplotlib.pyplot as plt +import numpy as np +from matplotlib.patches import Rectangle +from sklearn import model_selection + +import nemos as nmo + +np.random.seed(111) +# random design tensor. Shape (n_time_points, n_features). +X = 0.5*np.random.normal(size=(100, 5)) + +# log-rates & weights, shape (1, ) and (n_features, ) respectively. +b_true = np.zeros((1, )) +w_true = np.random.normal(size=(5, )) + +# sparsify weights +w_true[1:4] = 0. + +# generate counts +rate = jax.numpy.exp(jax.numpy.einsum("k,tk->t", w_true, X) + b_true) +spikes = np.random.poisson(rate) +``` + +## The Feed-Forward GLM + +### Model Definition +The class implementing the feed-forward GLM is `nemos.glm.GLM`. +In order to define the class, one **must** provide: + +- **Observation Model**: The observation model for the GLM, e.g. an object of the class of type +`nemos.observation_models.Observations`. So far, only the `PoissonObservations` +model has been implemented. +- **Regularizer**: The desired regularizer, e.g. an object of the `nemos.regularizer.Regularizer` class. +Currently, we implemented the un-regularized, Ridge, Lasso, and Group-Lasso regularization. + +The default for the GLM class is the `PoissonObservations` with log-link function with a Ridge regularization. +Here is how to define the model. + + +```{code-cell} ipython3 +# default Poisson GLM with Ridge regularization and Poisson observation model. +model = nmo.glm.GLM() + +print("Regularization type: ", type(model.regularizer)) +print("Observation model:", type(model.observation_model)) +``` + +### Model Configuration +One could visualize the model hyperparameters by calling `get_params` method. + + +```{code-cell} ipython3 +# get the glm model parameters only +print("\nGLM model parameters:") +for key, value in model.get_params(deep=False).items(): + print(f"\t- {key}: {value}") + +# get the glm model parameters, including the all the +# attributes +print("\nNested parameters:") +for key, value in model.get_params(deep=True).items(): + if key in model.get_params(deep=False): + continue + print(f"\t- {key}: {value}") +``` + +These parameters can be configured at initialization and/or +set after the model is initialized with the following syntax: + + +```{code-cell} ipython3 +# Poisson observation model with soft-plus NL +observation_models = nmo.observation_models.PoissonObservations(jax.nn.softplus) + + +# define the GLM +model = nmo.glm.GLM( + observation_model=observation_models, + solver_name="LBFGS", + solver_kwargs={"tol":10**-10}, +) + +print("Regularizer type: ", type(model.regularizer)) +print("Observation model:", type(model.observation_model)) +``` + +Hyperparameters can be set at any moment via the `set_params` method. + + +```{code-cell} ipython3 +model.set_params( + regularizer=nmo.regularizer.Lasso(), + observation_model__inverse_link_function=jax.numpy.exp +) + +print("Updated regularizer: ", model.regularizer) +print("Updated NL: ", model.observation_model.inverse_link_function) +``` + +!!! warning + Each `Regularizer` has an associated attribute `Regularizer.allowed_solvers` + which lists the optimizers that are suited for each optimization problem. + For example, a `Ridge` is differentiable and can be fit with `GradientDescent` + , `BFGS`, etc., while a `Lasso` should use the `ProximalGradient` method instead. + If the provided `solver_name` is not listed in the `allowed_solvers` this will raise an + exception. + + ++++ + +### Model Fit +Fitting the model is as straight forward as calling the `model.fit` +providing the design tensor and the population counts. +Additionally one may provide an initial parameter guess. +The same exact syntax works for any configuration. + + +```{code-cell} ipython3 +# fit a ridge regression Poisson GLM +model = nmo.glm.GLM(regularizer="Ridge", regularizer_strength=0.1) +model.fit(X, spikes) + +print("Ridge results") +print("True weights: ", w_true) +print("Recovered weights: ", model.coef_) +``` + +## K-fold Cross Validation with `sklearn` +Our implementation follows the `scikit-learn` api, this enables us +to take advantage of the `scikit-learn` tool-box seamlessly, while at the same time +we take advantage of the `jax` GPU acceleration and auto-differentiation in the +back-end. + +Here is an example of how we can perform 5-fold cross-validation via `scikit-learn`. + +**Ridge** + + +```{code-cell} ipython3 +parameter_grid = {"regularizer_strength": np.logspace(-1.5, 1.5, 6)} +# in practice, you should use more folds than 2, but for the purposes of this +# demo, 2 is sufficient. +cls = model_selection.GridSearchCV(model, parameter_grid, cv=2) +cls.fit(X, spikes) + +print("Ridge results ") +print("Best hyperparameter: ", cls.best_params_) +print("True weights: ", w_true) +print("Recovered weights: ", cls.best_estimator_.coef_) +``` + +We can compare the Ridge cross-validated results with other regularization schemes. + +**Lasso** + + +```{code-cell} ipython3 +model.set_params(regularizer=nmo.regularizer.Lasso(), solver_name="ProximalGradient") +cls = model_selection.GridSearchCV(model, parameter_grid, cv=2) +cls.fit(X, spikes) + +print("Lasso results ") +print("Best hyperparameter: ", cls.best_params_) +print("True weights: ", w_true) +print("Recovered weights: ", cls.best_estimator_.coef_) +``` + +**Group Lasso** + + +```{code-cell} ipython3 +# define groups by masking. Mask size (n_groups, n_features) +mask = np.zeros((2, 5)) +mask[0, [0, -1]] = 1 +mask[1, 1:-1] = 1 + +regularizer = nmo.regularizer.GroupLasso(mask=mask) +model.set_params(regularizer=regularizer, solver_name="ProximalGradient") +cls = model_selection.GridSearchCV(model, parameter_grid, cv=2) +cls.fit(X, spikes) + +print("\nGroup Lasso results") +print("Group mask: :") +print(mask) +print("Best hyperparameter: ", cls.best_params_) +print("True weights: ", w_true) +print("Recovered weights: ", cls.best_estimator_.coef_) +``` + +## Simulate Spikes +We can generate spikes in response to a feedforward-stimuli +through the `model.simulate` method. + + +```{code-cell} ipython3 +# here we are creating a new data input, of 20 timepoints (arbitrary) +# with the same number of features (mandatory) +Xnew = np.random.normal(size=(20, ) + X.shape[1:]) +# generate a random key given a seed +random_key = jax.random.key(123) +spikes, rates = model.simulate(random_key, Xnew) + +plt.figure() +plt.eventplot(np.where(spikes)[0]) +``` + +## Simulate a Recurrently Coupled Network +In this section, we will show you how to generate spikes from a population; We assume that the coupling +filters are known or inferred. + +!!! warning + Making sure that the dynamics of your recurrent neural network are stable is non-trivial[$^{[1]}$](#ref-1). In particular, + coupling weights obtained by fitting a GLM by maximum-likelihood can generate unstable dynamics. If the + dynamics of your recurrently coupled model are unstable, you can try a `soft-plus` non-linearity + instead of an exponential, and you can "shrink" your weights until stability is reached. + + + +```{code-cell} ipython3 +# Neural population parameters +n_neurons = 2 +coupling_filter_duration = 100 +``` + +Let's define the coupling filters that we will use to simulate +the pairwise interactions between the neurons. We will model the +filters as a difference of two Gamma probability density function. +The negative component will capture inhibitory effects such as the +refractory period of a neuron, while the positive component will +describe excitation. + + +```{code-cell} ipython3 +np.random.seed(101) + +# Gamma parameter for the inhibitory component of the filter +inhib_a = 1 +inhib_b = 1 + +# Gamma parameters for the excitatory component of the filter +excit_a = np.random.uniform(1.1, 5, size=(n_neurons, n_neurons)) +excit_b = np.random.uniform(1.1, 5, size=(n_neurons, n_neurons)) + +# define 2x2 coupling filters of the specific with create_temporal_filter +coupling_filter_bank = np.zeros((coupling_filter_duration, n_neurons, n_neurons)) +for unit_i in range(n_neurons): + for unit_j in range(n_neurons): + coupling_filter_bank[:, unit_i, unit_j] = nmo.simulation.difference_of_gammas( + coupling_filter_duration, + inhib_a=inhib_a, + excit_a=excit_a[unit_i, unit_j], + inhib_b=inhib_b, + excit_b=excit_b[unit_i, unit_j], + ) + +# shrink the filters for simulation stability +coupling_filter_bank *= 0.8 + +# define a basis function +n_basis_funcs = 20 +basis = nmo.basis.RaisedCosineBasisLog(n_basis_funcs) + +# approximate the coupling filters in terms of the basis function +_, coupling_basis = basis.evaluate_on_grid(coupling_filter_bank.shape[0]) +coupling_coeff = nmo.simulation.regress_filter(coupling_filter_bank, coupling_basis) +intercept = -4 * np.ones(n_neurons) +``` + +We can check that our approximation worked by plotting the original filters +and the basis expansion + + +```{code-cell} ipython3 +# plot coupling functions +n_basis_coupling = coupling_basis.shape[1] +fig, axs = plt.subplots(n_neurons, n_neurons) +plt.suptitle("Coupling filters") +for unit_i in range(n_neurons): + for unit_j in range(n_neurons): + axs[unit_i, unit_j].set_title(f"unit {unit_j} -> unit {unit_i}") + coeff = coupling_coeff[unit_i, unit_j] + axs[unit_i, unit_j].plot(coupling_filter_bank[:, unit_i, unit_j], label="gamma difference") + axs[unit_i, unit_j].plot(np.dot(coupling_basis, coeff), ls="--", color="k", label="basis function") +axs[0, 0].legend() +plt.tight_layout() +``` + +Define a squared stimulus current for the first neuron, and no stimulus for +the second neuron + + +```{code-cell} ipython3 +# define a squared current parameters +simulation_duration = 1000 +stimulus_onset = 200 +stimulus_offset = 500 +stimulus_intensity = 1.5 + +# create the input tensor of shape (n_samples, n_neurons, n_dimension_stimuli) +feedforward_input = np.zeros((simulation_duration, n_neurons, 1)) + +# inject square input to the first neuron only +feedforward_input[stimulus_onset: stimulus_offset, 0] = stimulus_intensity + +# plot the input +fig, axs = plt.subplots(1,2) +plt.suptitle("Feedforward inputs") +axs[0].set_title("Input to neuron 0") +axs[0].plot(feedforward_input[:, 0]) + +axs[1].set_title("Input to neuron 1") +axs[1].plot(feedforward_input[:, 1]) +axs[1].set_ylim(axs[0].get_ylim()) + + +# the input for the simulation will be the dot product +# of input_coeff with the feedforward_input +input_coeff = np.ones((n_neurons, 1)) + + +# initialize the spikes for the recurrent simulation +init_spikes = np.zeros((coupling_filter_duration, n_neurons)) +``` + +We can now simulate spikes by calling the `simulate_recurrent` function for the `nemos.simulate` module. + + +```{code-cell} ipython3 +# call simulate, with both the recurrent coupling +# and the input +spikes, rates = nmo.simulation.simulate_recurrent( + coupling_coef=coupling_coeff, + feedforward_coef=input_coeff, + intercepts=intercept, + random_key=jax.random.key(123), + feedforward_input=feedforward_input, + coupling_basis_matrix=coupling_basis, + init_y=init_spikes +) +``` + +And finally plot the results for both neurons. + + +```{code-cell} ipython3 +# mkdocs_gallery_thumbnail_number = 4 +plt.figure() +ax = plt.subplot(111) + +ax.spines['top'].set_visible(False) +ax.spines['right'].set_visible(False) + +patch = Rectangle((200, -0.011), 300, 0.15, alpha=0.2, color="grey") + +p0, = plt.plot(rates[:, 0]) +p1, = plt.plot(rates[:, 1]) + +plt.vlines(np.where(spikes[:, 0])[0], 0.00, 0.01, color=p0.get_color(), label="rate neuron 0") +plt.vlines(np.where(spikes[:, 1])[0], -0.01, 0.00, color=p1.get_color(), label="rate neuron 1") +plt.plot(jax.nn.softplus(input_coeff[0] * feedforward_input[:, 0, 0] + intercept[0]), color='k', lw=0.8, label="stimulus") +ax.add_patch(patch) +plt.ylim(-0.011, .13) +plt.ylabel("count/bin") +plt.legend() +``` + +## References +[1] Arribas, Diego, Yuan Zhao, and Il Memming Park. "Rescuing neural spike train models from bad MLE." Advances in Neural Information Processing Systems 33 (2020): 2293-2303. diff --git a/docs/how_to_guide/plot_03_glm_pytree.md b/docs/how_to_guide/plot_03_glm_pytree.md new file mode 100644 index 00000000..ea36b4b4 --- /dev/null +++ b/docs/how_to_guide/plot_03_glm_pytree.md @@ -0,0 +1,354 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +```{code-cell} ipython3 +%matplotlib inline +``` + +# FeaturePytree example + +This small example notebook shows how to use our custom FeaturePytree objects +instead of arrays to represent the design matrix. It will show that these two +representations are equivalent. + +This demo will fit the Poisson-GLM to some synthetic data. We will first show +the simple case, with a single neuron receiving some input. We will then show a +two-neuron system, to demonstrate how FeaturePytree can make it easier to +separate examine separate types of inputs. + +First, however, let's briefly discuss FeaturePytrees. + +```{code-cell} ipython3 +import jax +import jax.numpy as jnp +import numpy as np + +import nemos as nmo + +np.random.seed(111) +``` + +## FeaturePytrees + +A FeaturePytree is a custom NeMoS object used to represent design matrices, +GLM coefficients, and other similar variables. It is a simple +[pytree](https://jax.readthedocs.io/en/latest/pytrees.html), a dictionary +with strings as keys and arrays as values. These arrays must all have the +same number of elements along the first dimension, which represents the time +points, but can have different numbers of elements along the other dimensions +(and even different numbers of dimensions). + + +```{code-cell} ipython3 +example_pytree = nmo.pytrees.FeaturePytree(feature_0=np.random.normal(size=(100, 1, 2)), + feature_1=np.random.normal(size=(100, 2)), + feature_2=np.random.normal(size=(100, 5))) +example_pytree +``` + +FeaturePytrees can be indexed into like dictionary, so we can grab a +single one of their features: + + +```{code-cell} ipython3 +example_pytree['feature_0'].shape +``` + +We can grab the number of time points by getting the length or using the +`shape` attribute + + +```{code-cell} ipython3 +print(len(example_pytree)) +print(example_pytree.shape) +``` + +We can also jointly index into the FeaturePytree's leaves: + + +```{code-cell} ipython3 +example_pytree[:10] +``` + +We can add new features after initialization, as long as they have the same +number of time points. + + +```{code-cell} ipython3 +example_pytree['feature_3'] = np.zeros((100, 2, 4)) +``` + +However, if we try to add a new feature with the wrong number of time points, +we'll get an exception: + + +```{code-cell} ipython3 +try: + example_pytree['feature_4'] = np.zeros((99, 2, 4)) +except ValueError as e: + print(e) +``` + +Similarly, if we try to add a feature that's not an array: + + +```{code-cell} ipython3 +try: + example_pytree['feature_4'] = "Strings are very predictive" +except ValueError as e: + print(e) +``` + +FeaturePytrees are intended to be used with +[jax.tree_util.tree_map](https://jax.readthedocs.io/en/latest/_autosummary/jax.tree_util.tree_map.html), +a useful function for performing computations on arbitrary pytrees, +preserving their structure. + + ++++ + +We can map lambda functions: + + +```{code-cell} ipython3 +mapped = jax.tree_util.tree_map(lambda x: x**2, example_pytree) +print(mapped) +mapped['feature_1'] +``` + +Or functions from jax or numpy that operate on arrays: + + +```{code-cell} ipython3 +mapped = jax.tree_util.tree_map(jnp.exp, example_pytree) +print(mapped) +mapped['feature_1'] +``` + +We can change the dimensionality of our pytree: + + +```{code-cell} ipython3 +mapped = jax.tree_util.tree_map(lambda x: jnp.mean(x, axis=-1), example_pytree) +print(mapped) +mapped['feature_1'] +``` + +Or the number of time points: + + +```{code-cell} ipython3 +mapped = jax.tree_util.tree_map(lambda x: x[::10], example_pytree) +print(mapped) +mapped['feature_1'] +``` + +If we map something whose output cannot be a FeaturePytree (because its +values are scalars or non-arrays), we return a dictionary of arrays instead: + + +```{code-cell} ipython3 +print(jax.tree_util.tree_map(jnp.mean, example_pytree)) +print(jax.tree_util.tree_map(lambda x: x.shape, example_pytree)) +import matplotlib.pyplot as plt +import pynapple as nap +``` + +## FeaturePytrees and GLM + +These properties make FeaturePytrees useful for representing design matrices +and similar objects for the GLM. + +First, let's get our dataset and do some initial exploration of it. To do so, +we'll use pynapple to [stream +data](https://pynapple.org/examples/tutorial_pynapple_dandi.html) +from the DANDI archive. + +!!! attention + + We need some additional packages for this portion, which you can install + with `pip install dandi pynapple` + + +```{code-cell} ipython3 +io = nmo.fetch.download_dandi_data( + "000582", + "sub-11265/sub-11265_ses-07020602_behavior+ecephys.nwb", +) + +nwb = nap.NWBFile(io.read(), lazy_loading=False) + +print(nwb) +``` + +This data set has cells that are tuned for head direction and 2d position. +Let's compute some simple tuning curves to see if we can find a cell that +looks tuned for both. + + +```{code-cell} ipython3 +tc, binsxy = nap.compute_2d_tuning_curves(nwb['units'], nwb['SpatialSeriesLED1'].dropna(), 20) +fig, axes = plt.subplots(3, 3, figsize=(9, 9)) +for i, ax in zip(tc.keys(), axes.flatten()): + ax.imshow(tc[i], origin="lower", aspect="auto") + ax.set_title("Unit {}".format(i)) +axes[-1,-1].remove() +plt.tight_layout() + +# compute head direction. +diff = nwb['SpatialSeriesLED1'].values-nwb['SpatialSeriesLED2'].values +head_dir = np.arctan2(*diff.T) +head_dir = nap.Tsd(nwb['SpatialSeriesLED1'].index, head_dir) + +tune_head = nap.compute_1d_tuning_curves(nwb['units'], head_dir.dropna(), 30) + +fig, axes = plt.subplots(3, 3, figsize=(9, 9), subplot_kw={'projection': 'polar'}) +for i, ax in zip(tune_head.columns, axes.flatten()): + ax.plot(tune_head.index, tune_head[i]) + ax.set_title("Unit {}".format(i)) +axes[-1,-1].remove() +``` + +Okay, let's use unit number 7. + +Now let's set up our design matrix. First, let's fit the head direction by +itself. Head direction is a circular variable (pi and -pi are adjacent to +each other), so we need to use a basis that has this property as well. +`CyclicBSplineBasis` is one such basis. + +Let's create our basis and then arrange our data properly. + + +```{code-cell} ipython3 +unit_no = 7 +spikes = nwb['units'][unit_no] + +basis = nmo.basis.CyclicBSplineBasis(10, order=5) +x = np.linspace(-np.pi, np.pi, 100) +plt.figure() +plt.plot(x, basis(x)) + +# Find the interval on which head_dir has no NaNs +head_dir = head_dir.dropna() +# Grab the second (of two), since the first one is really short +valid_data= head_dir.time_support.loc[[1]] +head_dir = head_dir.restrict(valid_data) +# Count spikes at the same rate as head direction, over the same epoch +spikes = spikes.count(bin_size=1/head_dir.rate, ep=valid_data) +# the time points for spike are in the middle of these bins (whereas for +# head_dir they're at the ends), so use interpolate to shift head_dir to the +# center. +head_dir = head_dir.interpolate(spikes) + +X = nmo.pytrees.FeaturePytree(head_direction=basis(head_dir)) +``` + +Now we'll fit our GLM and then see what our head direction tuning looks like: + + +```{code-cell} ipython3 +model = nmo.glm.GLM(regularizer="Ridge", regularizer_strength=0.001) +model.fit(X, spikes) +print(model.coef_['head_direction']) + +bs_vis = basis(x) +tuning = jnp.einsum('b, tb->t', model.coef_['head_direction'], bs_vis) +plt.figure() +plt.polar(x, tuning) +``` + +This looks like a smoothed version of our tuning curve, like we'd expect! + +For a more direct comparison, we can plot the tuning function based on the model predicted +firing rates with that estimated from the counts. + + +```{code-cell} ipython3 +# predict rates and convert back to pynapple +rates_nap = nap.TsdFrame(t=head_dir.t, d=np.asarray(model.predict(X))) +# compute tuning function +tune_head_model = nap.compute_1d_tuning_curves_continuous(rates_nap, head_dir, 30) +# compare model prediction with data +fig, ax = plt.subplots(1, 1, subplot_kw={'projection': 'polar'}) +ax.plot(tune_head[7], label="counts") +# multiply by the sampling rate for converting to spike/sec. +ax.plot(tune_head_model * rates_nap.rate, label="model") + +# Let's compare this to using arrays, to see what it looks like: + +model = nmo.glm.GLM() +model.fit(X['head_direction'], spikes) +model.coef_ +``` + +We can see that the solution is identical, as is the way of interacting with +the GLM object. + +However, with a single type of feature, it's unclear why exactly this is +helpful. Let's add a feature for the animal's position in space. For this +feature, we need a 2d basis. Let's use some raised cosine bumps and organize +our data similarly. + + +```{code-cell} ipython3 +pos_basis = nmo.basis.RaisedCosineBasisLinear(10) * nmo.basis.RaisedCosineBasisLinear(10) +spatial_pos = nwb['SpatialSeriesLED1'].restrict(valid_data) + +X['spatial_position'] = pos_basis(*spatial_pos.values.T) +``` + +Running the GLM is identical to before, but we can see that our coef_ +FeaturePytree now has two separate keys, one for each feature type. + + +```{code-cell} ipython3 +model = nmo.glm.GLM(solver_name="LBFGS") +model.fit(X, spikes) +model.coef_ +``` + +Let's visualize our tuning. Head direction looks pretty much the same (though +the values are slightly different, as we can see when printing out the +coefficients). + + +```{code-cell} ipython3 +bs_vis = basis(x) +tuning = jnp.einsum('b,nb->n', model.coef_['head_direction'], bs_vis) +print(model.coef_['head_direction']) +plt.figure() +plt.polar(x, tuning.T) +``` + +And the spatial tuning again looks like a smoothed version of our earlier +tuning curves. + + +```{code-cell} ipython3 +_, _, pos_bs_vis = pos_basis.evaluate_on_grid(50, 50) +pos_tuning = jnp.einsum('b,ijb->ij', model.coef_['spatial_position'], pos_bs_vis) +plt.figure() +plt.imshow(pos_tuning) +``` + +We could do all this with matrices as well, but we have to pay attention to +indices in a way that is annoying: + + +```{code-cell} ipython3 +X_mat = nmo.utils.pynapple_concatenate_jax([X['head_direction'], X['spatial_position']], -1) + +model = nmo.glm.GLM() +model.fit(X_mat, spikes) +model.coef_[..., :basis.n_basis_funcs] +``` diff --git a/docs/how_to_guide/plot_04_population_glm.md b/docs/how_to_guide/plot_04_population_glm.md new file mode 100644 index 00000000..2a74ce93 --- /dev/null +++ b/docs/how_to_guide/plot_04_population_glm.md @@ -0,0 +1,219 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +```{code-cell} ipython3 +%matplotlib inline +``` + + +# Population GLM + +Fitting the activity of a neural population with NeMoS can be much more efficient than fitting each individual +neuron in a loop. The reason for this is that NeMoS leverages the powerful GPU-vectorization implemented by `JAX`. + + +!!! note + For an unregularized, Lasso, Ridge, or group-Lasso GLM, fitting a GLM one neuron at the time, or fitting jointly + the neural population is equivalent. The main difference between the approaches is that the former is more + memory efficient, the latter is computationally more efficient (it takes less time to fit). + +## Fitting a Population GLM + +NeMoS has a dedicated `nemos.GLM.PopulationGLM` class for fitting jointly a neural population. The API + is very similar to that the regular `nemos.glm.GLM`, but with a few differences: + + 1. The `y` input to the methods `fit` and `score` must be a two-dimensional array of shape `(n_samples, n_neurons)`. + 2. You can optionally pass a `feature_mask` in the form of an array of 0s and 1s with shape `(n_features, n_neurons)` + that specifies which features are used as predictors for each neuron. More on this [later](#neuron-specific-features). + +Let's generate some synthetic data and fit a population model. + +```{code-cell} ipython3 +import jax.numpy as jnp +import matplotlib.pyplot as plt +import numpy as np + +import nemos as nmo + +np.random.seed(123) + +n_features = 5 +n_neurons = 2 +n_samples = 500 + +# random design array. Shape (n_time_points, n_features). +X = 0.5*np.random.normal(size=(n_samples, n_features)) + +# log-rates & weights +b_true = np.zeros((n_neurons, )) +w_true = np.random.uniform(size=(n_features, n_neurons)) + + +# generate counts (spikes will be (n_samples, n_features) +rate = jnp.exp(jnp.dot(X, w_true) + b_true) +spikes = np.random.poisson(rate) + +print(spikes.shape) +``` + +We can now instantiate the `PopulationGLM` model and fit. + + +```{code-cell} ipython3 +model = nmo.glm.PopulationGLM() +model.fit(X, spikes) + +print(f"population GLM log-likelihood: {model.score(X, spikes)}") +``` + +## Neuron-specific features +If you want to model neurons with different input features, the way to do so is to specify a `feature_mask`. +Let's assume that we have two neurons, share one shared input, and have an extra private one, for a total of +3 inputs. + + +```{code-cell} ipython3 +# let's take the first three input +n_features = 3 +input_features = X[:, :3] +``` + +Let's assume that: + + - `input_features[:, 0]` is shared. + - `input_features[:, 1]` is an input only for the first neuron. + - `input_features[:, 2]` is an input only for the second neuron. + +We can simulate this scenario, + + +```{code-cell} ipython3 +# model the rate of the first neuron using only the first two features and weights. +rate_neuron_1 = jnp.exp(np.dot(input_features[:, [0, 1]], w_true[: 2, 0])) + +# model the rate of the second neuron using only the first and last feature and weights. +rate_neuron_2 = jnp.exp(np.dot(input_features[:, [0, 2]], w_true[[0, 2], 1])) + +# stack the rates in a (n_samples, n_neurons) array and generate spikes +rate = np.hstack((rate_neuron_1[:, np.newaxis], rate_neuron_2[:, np.newaxis])) +spikes = np.random.poisson(rate) +``` + +We can impose the same constraint to the `PopulationGLM` by masking the weights. + + +```{code-cell} ipython3 +# initialize the mask to a matrix of 1s. +feature_mask = np.ones((n_features, n_neurons)) + +# remove the 3rd feature from the predictors of the first neuron +feature_mask[2, 0] = 0 + +# remove the 2nd feature from the predictors of the second neuron +feature_mask[1, 1] = 0 + +# visualize the mask +print(feature_mask) +``` + +The mask can be passed at initialization or set after the model is initialized, but cannot be changed +after the model is fit. + + +```{code-cell} ipython3 +# set a quasi-newton solver and low tolerance for better numerical precision +model = nmo.glm.PopulationGLM(solver_name="LBFGS", solver_kwargs={"tol": 10**-12}) + +# set the mask +model.feature_mask = feature_mask + +# fit the model +model.fit(input_features, spikes) +``` + +If we print the model coefficients, we can see the effect of the mask. + + +```{code-cell} ipython3 +print(model.coef_) +``` + +The coefficient for the first neuron corresponding to the last feature is zero, as well as +the coefficient of the second neuron corresponding to the second feature. + +To convince ourselves that this is equivalent to fit each neuron individually with the correct features, +let's go ahead and try. + + +```{code-cell} ipython3 +# features for each neuron +features_by_neuron = { + 0: [0, 1], + 1: [0, 2] +} +# initialize the coefficients +coeff = np.zeros((2, 2)) + +# loop over the neurons and fit a GLM +for neuron in range(2): + model_neu = nmo.glm.GLM( + solver_name="LBFGS", solver_kwargs={"tol":10**-12} + ) + model_neu.fit(input_features[:, features_by_neuron[neuron]], spikes[:, neuron]) + coeff[:, neuron] = model_neu.coef_ + +# visually compare the estimated coeffeicients +fig, axs = plt.subplots(1, 2, figsize=(6, 3)) +for neuron in range(2): + axs[neuron].set_title(f"neuron {neuron}") + axs[neuron].bar([0, 4], w_true[features_by_neuron[neuron], neuron], width=0.8, label="true") + axs[neuron].bar([1, 5], coeff[:, neuron], width=0.8, label="single neuron GLM") + axs[neuron].bar([2, 6], model.coef_[features_by_neuron[neuron], neuron], width=0.8, label="population GLM") + axs[neuron].set_ylabel("coefficient") + axs[neuron].set_ylim(0, 0.8) + axs[neuron].set_xticks([0.5, 3.5]) + axs[neuron].set_xticklabels(["feature 0", f"feature {neuron + 1}"]) + if neuron == 1: + plt.legend() +plt.tight_layout() +``` + +## FeaturePytree +`PopulationGLM` is compatible with [`FeaturePytree`](../plot_03_glm_pytree). If you structured your predictors +in a `FeaturePytree`, the `feature_mask` needs to be a dictionary of the same structure, containing arrays +of shape `(n_neurons, )`. +The example above can be reformulated as follows, + + +```{code-cell} ipython3 +# restructure the input as FeaturePytree +pytree_features = nmo.pytrees.FeaturePytree( + shared=input_features[:, :1], + neu_0=input_features[:, 1:2], + neu_1=input_features[:, 2:] +) + +# Define a mask as a dictionary +pytree_mask = dict( + shared=np.array([1, 1]), + neu_0=np.array([1, 0]), + neu_1=np.array([0, 1]) +) + +# fit a model +model_tree = nmo.glm.PopulationGLM(solver_name="LBFGS", feature_mask=pytree_mask) +model_tree.fit(pytree_features, spikes) + +# print the coefficients +print(model_tree.coef_) +``` diff --git a/docs/how_to_guide/plot_05_batch_glm.md b/docs/how_to_guide/plot_05_batch_glm.md new file mode 100644 index 00000000..ef7566c0 --- /dev/null +++ b/docs/how_to_guide/plot_05_batch_glm.md @@ -0,0 +1,243 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +```{code-cell} ipython3 +%matplotlib inline +``` + + +# Batching example + +Here we demonstrate how to setup and run a stochastic gradient descent in `nemos` +by batching and using the `update` method of the model class. + +```{code-cell} ipython3 +import matplotlib.pyplot as plt +import numpy as np +import pynapple as nap + +import nemos as nmo + +nap.nap_config.suppress_conversion_warnings = True + +# set random seed +np.random.seed(123) +``` + +## Simulate data + +Let's generate some data artificially + + +```{code-cell} ipython3 +n_neurons = 10 +T = 50 + +times = np.linspace(0, T, 5000).reshape(-1, 1) +rate = np.exp(np.sin(times + np.linspace(0, np.pi*2, n_neurons).reshape(1, n_neurons))) +``` + +Get the spike times from the rate and generate a `TsGroup` object + + +```{code-cell} ipython3 +spike_t, spike_id = np.where(np.random.poisson(rate)) +units = nap.Tsd(spike_t/T, spike_id).to_tsgroup() +``` + +## Model configuration + +Let's imagine this dataset do not fit in memory. We can use a batching approach to train the GLM. +First we need to instantiate the `PopulationGLM`. The default algorithm for `PopulationGLM` is gradient descent. +We suggest to use it for batching. + +!!! Note + You must shutdown the dynamic update of the step for fitting a batched (also called stochastic) gradient descent. + In jaxopt, this can be done by setting the parameters `acceleration` to False and setting the `stepsize`. + + + +```{code-cell} ipython3 +glm = nmo.glm.PopulationGLM( + solver_name="GradientDescent", + solver_kwargs={"stepsize": 0.1, "acceleration": False} + ) +``` + +## Basis instantiation + +Here we instantiate the basis. `ws` is 40 time bins. It corresponds to a 200 ms windows + + +```{code-cell} ipython3 +ws = 40 +basis = nmo.basis.RaisedCosineBasisLog(5, mode="conv", window_size=ws) +``` + +## Batch definition + +The batch size needs to be larger than the window size of the convolution kernel defined above. + + +```{code-cell} ipython3 +batch_size = 5 # second +``` + +Here we define a batcher function that generate a random 5 s of design matrix and spike counts. +This function will be called during each iteration of the stochastic gradient descent. + + +```{code-cell} ipython3 +def batcher(): + # Grab a random time within the time support. Here is the time support is one epoch only so it's easy. + t = np.random.uniform(units.time_support[0, 0], units.time_support[0, 1]-batch_size) + + # Bin the spike train in a 1s batch + ep = nap.IntervalSet(t, t+batch_size) + counts = units.restrict(ep).count(0.005) # count in 5 ms bins + + # Convolve + X = basis.compute_features(counts) + + # Return X and counts + return X, counts +``` + +## Solver initialization + +First we need to initialize the gradient descent solver within the `PopulationGLM`. +This gets you the initial parameters and the first state of the solver. + + +```{code-cell} ipython3 +params = glm.initialize_params(*batcher()) +state = glm.initialize_state(*batcher(), params) +``` + +## Batch learning + +Let's do a few iterations of gradient descent calling the `batcher` function at every step. +At each step, we store the log-likelihood of the model for each neuron evaluated on the batch + + +```{code-cell} ipython3 +n_step = 500 +logl = np.zeros(n_step) + +for i in range(n_step): + + # Get a batch of data + X, Y = batcher() + + # Do one step of gradient descent. + params, state = glm.update(params, state, X, Y) + + # Score the model along the time axis + logl[i] = glm.score(X, Y, score_type="log-likelihood") +``` + +!!! Warning "Input validation" + The `update` method does not perform input validation each time it is called. + This design choice speeds up computation by avoiding repetitive checks. However, + it requires that all inputs to the `update` method strictly conform to the expected + dimensionality and structure as established during the initialization of the solver. + Failure to comply with these expectations will likely result in runtime errors or + incorrect computations. + +First let's plot the log-likelihood to see if the model is converging. + + +```{code-cell} ipython3 +plt.figure() +plt.plot(logl) +plt.xlabel("Iteration") +plt.ylabel("Log-likelihood") +plt.show() +``` + +We can see that the log-likelihood is increasing but did not reach plateau yet. +The number of iterations can be increased to continue learning. + +We can take a look at the coefficients. +Here we extract the weight matrix of shape `(n_neurons*n_basis, n_neurons)` +and reshape it to `(n_neurons, n_basis, n_neurons)`. +We then average along basis to get a weight matrix of shape `(n_neurons, n_neurons)`. + + +```{code-cell} ipython3 +W = glm.coef_.reshape(len(units), basis.n_basis_funcs, len(units)) +Wm = np.mean(np.abs(W), 1) + +# Let's plot it. + +plt.figure() +plt.imshow(Wm) +plt.xlabel("Neurons") +plt.ylabel("Neurons") +plt.show() +``` + +## Model comparison + +Since this example is small enough, we can fit the full model and compare the scores. +Here we generate the design matrix and spike counts for the whole dataset. + + +```{code-cell} ipython3 +Y = units.count(0.005) +X = basis.compute_features(Y) +full_model = nmo.glm.PopulationGLM().fit(X, Y) +``` + +Now that the full model is fitted, we are scoring the full model and the batch model against the full datasets to compare the scores. +The score is pseudo-R2 + + +```{code-cell} ipython3 +full_scores = full_model.score( + X, Y, aggregate_sample_scores=lambda x:np.mean(x, axis=0), score_type="pseudo-r2-McFadden" +) +batch_scores = glm.score( + X, Y, aggregate_sample_scores=lambda x:np.mean(x, axis=0), score_type="pseudo-r2-McFadden" +) +``` + +Let's compare scores for each neurons as well as the coefficients. + + +```{code-cell} ipython3 +plt.figure(figsize=(10, 8)) +gs = plt.GridSpec(3,2) +plt.subplot(gs[0,:]) +plt.bar(np.arange(0, n_neurons), full_scores, 0.4, label="Full model") +plt.bar(np.arange(0, n_neurons)+0.5, batch_scores, 0.4, label="Batch model") +plt.ylabel("Pseudo R2") +plt.xlabel("Neurons") +plt.ylim(0, 1) +plt.legend() +plt.subplot(gs[1:,0]) +plt.imshow(Wm) +plt.title("Batch model") +plt.subplot(gs[1:,1]) +Wm2 = np.mean( + np.abs( + full_model.coef_.reshape(len(units), basis.n_basis_funcs, len(units)) + ) + , 1) +plt.imshow(Wm2) +plt.title("Full model") +plt.tight_layout() +plt.show() +``` + +As we can see, with a few iterations, the batch model manage to recover a similar coefficient matrix. diff --git a/docs/how_to_guide/plot_06_sklearn_pipeline_cv_demo.md b/docs/how_to_guide/plot_06_sklearn_pipeline_cv_demo.md new file mode 100644 index 00000000..35ff196a --- /dev/null +++ b/docs/how_to_guide/plot_06_sklearn_pipeline_cv_demo.md @@ -0,0 +1,552 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +```{code-cell} ipython3 +%matplotlib inline +``` + + +# Selecting basis by cross-validation with scikit-learn + +In this demo, we will demonstrate how to select an appropriate basis and its hyperparameters using cross-validation. +In particular, we will learn: + +1. What a scikit-learn pipeline is. +2. Why pipelines are useful. +3. How to combine NeMoS `Basis` and `GLM` objects in a pipeline. +4. How to select the number of bases and the basis type through cross-validation (or any other hyperparameter in the pipeline). +5. How to use a custom scoring metric to quantify the performance of each configuration. + ++++ + +## What is a scikit-learn pipeline + +
+Pipeline illustration. +
Schematic of a scikit-learn pipeline.
+
+ +A pipeline is a sequence of data transformations leading up to a model. Each step before the final one transforms the input data into a different representation, and then the final model step fits, predicts, or scores based on the previous step's output and some observations. Setting up such machinery can be simplified using the `Pipeline` class from scikit-learn. + +To set up a scikit-learn `Pipeline`, ensure that: + +1. Each intermediate step is a [scikit-learn transformer object](https://scikit-learn.org/stable/data_transforms.html) with a `transform` and/or `fit_transform` method. +2. The final step is an [estimator object](https://scikit-learn.org/stable/developers/develop.html#estimators) with a `fit` method, or a model with `fit`, `predict`, and `score` methods. + +Each transformation step takes a 2D array `X` of shape `(num_samples, num_original_features)` as input and outputs another 2D array of shape `(num_samples, num_transformed_features)`. The final step takes a pair `(X, y)`, where `X` is as before, and `y` is a 1D array of shape `(n_samples,)` containing the observations to be modeled. + +You can define a pipeline as follows: +```python +from sklearn.pipeline import Pipeline + +# Assume transformer_i/predictor is a transformer/model object +pipe = Pipeline( + [ + ("label_1", transformer_1), + ("label_2", transformer_2), + ..., + ("label_n", transformer_n), + ("label_model", model) + ] +) +``` + +Note that you have to assign a label to each step of the pipeline. +!!! tip + Here we used a placeholder `"label_i"` for demonstration; you should choose a more descriptive name depending on the type of transformation step. + +Calling `pipe.fit(X, y)` will perform the following computations: +```python +# Chain of transformations +X1 = transformer_1.fit_transform(X) +X2 = transformer_2.fit_transform(X1) +# ... +Xn = transformer_n.fit_transform(Xn_1) + +# Fit step +model.fit(Xn, y) +``` +And the same holds for `pipe.score` and `pipe.predict`. + +## Why pipelines are useful + +Pipelines not only streamline and simplify your code but also offer several other advantages. The real power of pipelines becomes evident when combined with the scikit-learn `model_selection` module, which includes cross-validation and similar methods. This combination allows you to tune hyperparameters at each step of the pipeline in a straightforward manner. + +In the following sections, we will showcase this approach with a concrete example: selecting the appropriate basis type and number of bases for a GLM regression in NeMoS. + +## Combining basis transformations and GLM in a pipeline +Let's start by creating some toy data. + + +```{code-cell} ipython3 +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import scipy.stats +import seaborn as sns +from sklearn.model_selection import GridSearchCV +from sklearn.pipeline import Pipeline + +import nemos as nmo + +# some helper plotting functions +from nemos import _documentation_utils as doc_plots + +# predictors, shape (n_samples, n_features) +X = np.random.uniform(low=0, high=1, size=(1000, 1)) +# observed counts, shape (n_samples,) +rate = 2 * ( + scipy.stats.norm.pdf(X, scale=0.1, loc=0.25) + + scipy.stats.norm.pdf(X, scale=0.1, loc=0.75) +) +y = np.random.poisson(rate).astype(float).flatten() +``` + +Let's now plot the simulated neuron's tuning curve, which is bimodal, Gaussian-shaped, and has peaks at 0.25 and 0.75. + + +```{code-cell} ipython3 +fig, ax = plt.subplots() +ax.scatter(X.flatten(), y, alpha=0.2) +ax.set_xlabel("input") +ax.set_ylabel("spike count") +sns.despine(ax=ax) +``` + +### Converting NeMoS `Basis` to a transformer +In order to use NeMoS `Basis` in a pipeline, we need to convert it into a scikit-learn transformer. This can be achieved through the `TransformerBasis` wrapper class. + +Instantiating a `TransformerBasis` can be done either using the constructor directly or with `Basis.to_transformer()`: + + +```{code-cell} ipython3 +bas = nmo.basis.RaisedCosineBasisLinear(5, mode="conv", window_size=5) +# these two ways of creating the TransformerBasis are equivalent +trans_bas_a = nmo.basis.TransformerBasis(bas) +trans_bas_b = bas.to_transformer() +``` + +`TransformerBasis` provides convenient access to the underlying `Basis` object's attributes: + + +```{code-cell} ipython3 +print(bas.n_basis_funcs, trans_bas_a.n_basis_funcs, trans_bas_b.n_basis_funcs) +``` + +We can also set attributes of the underlying `Basis`. Note that -- because `TransformerBasis` is created with a copy of the `Basis` object passed to it -- this does not change the original `Basis`, and neither does changing the original `Basis` change `TransformerBasis` we created: + + +```{code-cell} ipython3 +trans_bas_a.n_basis_funcs = 10 +bas.n_basis_funcs = 100 + +print(bas.n_basis_funcs, trans_bas_a.n_basis_funcs, trans_bas_b.n_basis_funcs) +``` + +### Creating and fitting a pipeline +We might want to combine first transforming the input data with our basis functions, then fitting a GLM on the transformed data. + +This is exactly what `Pipeline` is for! + + +```{code-cell} ipython3 +pipeline = Pipeline( + [ + ( + "transformerbasis", + nmo.basis.TransformerBasis(nmo.basis.RaisedCosineBasisLinear(6)), + ), + ( + "glm", + nmo.glm.GLM(regularizer_strength=0.5, regularizer="Ridge"), + ), + ] +) + +pipeline.fit(X, y) +``` + +Note how NeMoS models are already scikit-learn compatible and can be used directly in the pipeline. + +Visualize the fit: + + +```{code-cell} ipython3 +# Predict the rate. +# Note that you need a 2D input even if x is a flat array. +# We are using expand dim to add the extra-dimension +x = np.sort(X, axis=0) +predicted_rate = pipeline.predict(x) +``` + +```{code-cell} ipython3 +fig, ax = plt.subplots() + +ax.scatter(X.flatten(), y, alpha=0.2, label="generated spike counts") +ax.set_xlabel("input") +ax.set_ylabel("spike count") + + +ax.plot( + x, + predicted_rate, + label="predicted rate", + color="tab:orange", +) + +ax.legend() +sns.despine(ax=ax) +``` + +The current model captures the bimodal distribution of responses, appropriately picking out the peaks. However, it doesn't do a good job capturing the actual firing rate: the peaks are too low and the valleys are not low enough. This might be because of our choice of basis and/or regularizer strength, so let's see if tuning those parameters results in a better fit! We could do this manually, but doing this with the sklearn pipeline will make everything much easier! + + ++++ + +### Select the number of basis by cross-validation + + ++++ + +!!! warning + Please keep in mind that while `GLM.score` supports different ways of evaluating goodness-of-fit through the `score_type` argument, `pipeline.score(X, y, score_type="...")` does not propagate this, and uses the default value of `log-likelihood`. + + To evaluate a pipeline, please create a custom scorer (e.g. `pseudo_r2` below) and call `my_custom_scorer(pipeline, X, y)`. + +#### Define the parameter grid + +Let's define candidate values for the parameters of each step of the pipeline we want to cross-validate. In this case the number of basis functions in the transformation step and the ridge regularization's strength in the GLM fit: + + +```{code-cell} ipython3 +param_grid = dict( + glm__regularizer_strength=(0.1, 0.01, 0.001, 1e-6), + transformerbasis__n_basis_funcs=(3, 5, 10, 20, 100), +) +``` + +!!! note "Grid definition" + In order to define a parameter grid dictionary for a pipeline, you must structure the dictionary keys as follows: + + - Start with the pipeline label (`"glm"` or `"transformerbasis"` for us). This determines which pipeline step has the relevant hyperparameter. + - Add `"__"` followed by the hyperparameter name (for example, `"n_basis_funcs"`). + - If the hyperparameter is itself an object with attributes, add another `"__"` followed by the attribute name. For instance, `"glm__observation_model__inverse_link_function"` + would be a valid key for cross-validating over the link function of the GLM's `observation_model` attribute `inverse_link_function`. + The values in the dictionary are the parameters to be tested. + + ++++ + +#### Run the grid search +Let's run a 5-fold cross-validation of the hyperparameters with the scikit-learn `model_selection.GridsearchCV` class. +??? info "K-Fold cross-validation" +

+ Grid Search Cross Validation +
+ K-fold cross-validation (modified from scikit-learn docs) +

+ K-fold cross-validation is a robust method used for selecting hyperparameters. In this procedure, the data is divided into K equally sized chunks (or folds). The model is trained on K-1 of these chunks, with the remaining chunk used for evaluation. This process is repeated K times, with each chunk being used exactly once as the evaluation set. + After completing the K iterations, the K evaluation scores are averaged to provide a reliable estimate of the model's performance. To select the optimal hyperparameters, K-fold cross-validation can be applied over a grid of potential hyperparameters, with the set yielding the highest average score being chosen as the best. + + +```{code-cell} ipython3 +gridsearch = GridSearchCV( + pipeline, + param_grid=param_grid, + cv=5 +) + +# run the 5-fold cross-validation grid search +gridsearch.fit(X, y) +``` + +??? note "Manual cross-validation" + To appreciate how much boiler-plate code we are saving by calling scikit-learn cross-validation, below + we can see how this cross-validation will look like in a manual loop. + + ```python + from itertools import product + from copy import deepcopy + + regularizer_strength = (0.1, 0.01, 0.001, 1e-6) + n_basis_funcs = (3, 5, 10, 20, 100) + + # define the folds + n_folds = 5 + fold_idx = np.arange(X.shape[0] - X.shape[0] % n_folds).reshape(n_folds, -1) + + + # Initialize the scores + scores = np.zeros((len(regularizer_strength) * len(n_basis_funcs), n_folds)) + + # Dictionary to store coefficients + coeffs = {} + + # initialize basis and model + basis = nmo.basis.TransformerBasis(nmo.basis.RaisedCosineBasisLinear(6)) + model = nmo.glm.GLM(regularizer="Ridge") + + # loop over combinations + for fold in range(n_folds): + test_idx = fold_idx[fold] + train_idx = fold_idx[[x for x in range(n_folds) if x != fold]].flatten() + for i, params in enumerate(product(regularizer_strength, n_basis_funcs)): + reg_strength, n_basis = params + + # deepcopy the basis and model + bas = deepcopy(basis) + glm = deepcopy(model) + + # set the parameters + bas.n_basis_funcs = n_basis + glm.regularizer_strength = reg_strength + + # fit the model + glm.fit(bas.transform(X[train_idx]), y[train_idx]) + + # store score and coefficients + scores[i, fold] = glm.score(bas.transform(X[test_idx]), y[test_idx]) + coeffs[(i, fold)] = (glm.coef_, glm.intercept_) + + # get the best mean test score + i_best = np.argmax(scores.mean(axis=1)) + # get the overall best coeffs + fold_best = np.argmax(scores[i_best]) + + # set up the best model + model.coef_ = coeffs[(i_best, fold_best)][0] + model.intercept_ = coeffs[(i_best, fold_best)][1] + + # get the best hyperparameters + best_reg_strength = regularizer_strength[i_best // len(n_basis_funcs)] + best_n_basis = n_basis_funcs[i_best % len(n_basis_funcs)] + ``` + + ++++ + +#### Visualize the scores + +Let's extract the scores from `gridsearch` and take a look at how the different parameter values of our pipeline influence the test score: + + +```{code-cell} ipython3 +cvdf = pd.DataFrame(gridsearch.cv_results_) + +cvdf_wide = cvdf.pivot( + index="param_transformerbasis__n_basis_funcs", + columns="param_glm__regularizer_strength", + values="mean_test_score", +) + +doc_plots.plot_heatmap_cv_results(cvdf_wide) +``` + +The plot displays the model's log-likelihood for each parameter combination in the grid. The parameter combination with the highest score, which is the one selected by the procedure, is highlighted with a blue rectangle. We can thus see that we need 10 or more basis functions, and that all of the tested regularization strengths agree with each other. In general, we want the fewest number of basis functions required to get a good fit, so we'll choose 10 here. + +#### Visualize the predicted rate +Finally, visualize the predicted firing rates using the best model found by our grid-search, which gives a better fit than the randomly chosen parameter values we tried in the beginning: + + +```{code-cell} ipython3 +# Predict the ate using the best configuration, +x = np.sort(X, axis=0) +predicted_rate = gridsearch.best_estimator_.predict(x) +``` + +```{code-cell} ipython3 +fig, ax = plt.subplots() + +ax.scatter(X.flatten(), y, alpha=0.2, label="generated spike counts") +ax.set_xlabel("input") +ax.set_ylabel("spike count") + + +ax.plot( + x, + predicted_rate, + label="predicted rate", + color="tab:orange", +) + +ax.legend() +sns.despine(ax=ax) +``` + +:rocket::rocket::rocket: **Success!** :rocket::rocket::rocket: +We are now able to capture the distribution of the firing rate appropriately: both peaks and valleys in the spiking activity are matched by our model predicitons. + +### Evaluating different bases directly + +In the previous example we set the number of basis functions of the `Basis` wrapped in our `TransformerBasis`. However, if we are for example not sure about the type of basis functions we want to use, or we have already defined some basis functions of our own, then we can use cross-validation to directly evaluate those as well. + +Here we include `transformerbasis___basis` in the parameter grid to try different values for `TransformerBasis._basis`: + + +```{code-cell} ipython3 +param_grid = dict( + glm__regularizer_strength=(0.1, 0.01, 0.001, 1e-6), + transformerbasis___basis=( + nmo.basis.RaisedCosineBasisLinear(5), + nmo.basis.RaisedCosineBasisLinear(10), + nmo.basis.RaisedCosineBasisLog(5), + nmo.basis.RaisedCosineBasisLog(10), + nmo.basis.MSplineBasis(5), + nmo.basis.MSplineBasis(10), + ), +) +``` + +Then run the grid search: + + +```{code-cell} ipython3 +gridsearch = GridSearchCV( + pipeline, + param_grid=param_grid, + cv=5, +) + +# run the 5-fold cross-validation grid search +gridsearch.fit(X, y) +``` + +Wrangling the output data a bit and looking at the scores: + + +```{code-cell} ipython3 +cvdf = pd.DataFrame(gridsearch.cv_results_) + +# Read out the number of basis functions +cvdf["transformerbasis_config"] = [ + f"{b.__class__.__name__} - {b.n_basis_funcs}" + for b in cvdf["param_transformerbasis___basis"] +] + +cvdf_wide = cvdf.pivot( + index="transformerbasis_config", + columns="param_glm__regularizer_strength", + values="mean_test_score", +) + +doc_plots.plot_heatmap_cv_results(cvdf_wide) +``` + +As shown in the table, the model with the highest score, highlighted in blue, used a RaisedCosineBasisLinear basis (as used above), which appears to be a suitable choice for our toy data. +We can confirm that by plotting the firing rate predictions: + + +```{code-cell} ipython3 +# Predict the rate using the optimal configuration +x = np.sort(X, axis=0) +predicted_rate = gridsearch.best_estimator_.predict(x) +``` + +```{code-cell} ipython3 +fig, ax = plt.subplots() + +ax.scatter(X.flatten(), y, alpha=0.2, label="generated spike counts") +ax.set_xlabel("input") +ax.set_ylabel("spike count") + +ax.plot( + x, + predicted_rate, + label="predicted rate", + color="tab:orange", +) + +ax.legend() +sns.despine(ax=ax) +``` + +The plot confirms that the firing rate distribution is accurately captured by our model predictions. + + ++++ + +!!! warning + Please note that because it would lead to unexpected behavior, mixing the two ways of defining values for the parameter grid is not allowed. The following would lead to an error: + + ```python + param_grid = dict( + glm__regularizer_strength=(0.1, 0.01, 0.001, 1e-6), + transformerbasis__n_basis_funcs=(3, 5, 10, 20, 100), + transformerbasis___basis=( + nmo.basis.RaisedCosineBasisLinear(5), + nmo.basis.RaisedCosineBasisLinear(10), + nmo.basis.RaisedCosineBasisLog(5), + nmo.basis.RaisedCosineBasisLog(10), + nmo.basis.MSplineBasis(5), + nmo.basis.MSplineBasis(10), + ), + ) + ``` + + ++++ + +## Create a custom scorer +By default, the GLM score method returns the model log-likelihood. If you want to try a different metric, such as the pseudo-R2, you can create a custom scorer and pass it to the cross-validation object: + + +```{code-cell} ipython3 +from sklearn.metrics import make_scorer + +pseudo_r2 = make_scorer( + nmo.observation_models.PoissonObservations().pseudo_r2 +) +``` + +We can now run the grid search providing the custom scorer + + +```{code-cell} ipython3 +gridsearch = GridSearchCV( + pipeline, + param_grid=param_grid, + cv=5, + scoring=pseudo_r2, +) + +# Run the 5-fold cross-validation grid search +gridsearch.fit(X, y) +``` + +And finally, we can plot each model's score. + + ++++ + +Plot the pseudo-R2 scores + + +```{code-cell} ipython3 +cvdf = pd.DataFrame(gridsearch.cv_results_) + +# Read out the number of basis functions +cvdf["transformerbasis_config"] = [ + f"{b.__class__.__name__} - {b.n_basis_funcs}" + for b in cvdf["param_transformerbasis___basis"] +] + +cvdf_wide = cvdf.pivot( + index="transformerbasis_config", + columns="param_glm__regularizer_strength", + values="mean_test_score", +) + +doc_plots.plot_heatmap_cv_results(cvdf_wide, label="pseudo-R2") +``` + +As you can see, the results with pseudo-R2 agree with those of the negative log-likelihood. Note that this new metric is normalized between 0 and 1, with a higher score indicating better performance. diff --git a/docs/index.md b/docs/index.md index 54d3cf72..e24e00cb 100644 --- a/docs/index.md +++ b/docs/index.md @@ -110,12 +110,6 @@ Explore fully worked examples to learn how to analyze neural recordings from scr Access a detailed description of each module and function, including parameters and functionality. - - ::: :::: diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md new file mode 100644 index 00000000..65761d86 --- /dev/null +++ b/docs/tutorials/plot_01_current_injection.md @@ -0,0 +1,730 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +```{code-cell} ipython3 +%matplotlib inline +``` + +# Fit injected current + +For our first example, we will look at a very simple dataset: patch-clamp +recordings from a single neuron in layer 4 of mouse primary visual cortex. This +data is from the [Allen Brain +Atlas](https://celltypes.brain-map.org/experiment/electrophysiology/478498617), +and experimenters injected current directly into the cell, while recording the +neuron's membrane potential and spiking behavior. The experiments varied the +shape of the current across many sweeps, mapping the neuron's behavior in +response to a wide range of potential inputs. + +For our purposes, we will examine only one of these sweeps, "Noise 1", in which +the experimentalists injected three pulses of current. The current is a square +pulse multiplied by a sinusoid of a fixed frequency, with some random noise +riding on top. + +![Allen Brain Atlas view of the data we will analyze.](../../assets/allen_data.png) + +In the figure above (from the Allen Brain Atlas website), we see the +approximately 22 second sweep, with the input current plotted in the first row, +the intracellular voltage in the second, and the recorded spikes in the third. +(The grey lines and dots in the second and third rows comes from other sweeps +with the same stimulus, which we'll ignore in this exercise.) When fitting the +Generalized Linear Model, we are attempting to model the spiking behavior, and +we generally do not have access to the intracellular voltage, so for the rest +of this notebook, we'll use only the input current and the recorded spikes +displayed in the first and third rows. + +First, let us see how to load in the data and reproduce the above figure, which +we'll do using the [Pynapple package](https://pynapple-org.github.io/pynapple/). We will rely on +pynapple throughout this notebook, as it simplifies handling this type of +data (we will explain the essentials of pynapple as they are used, but see the +[Pynapple docs](https://pynapple-org.github.io/pynapple/) +if you are interested in learning more). After we've explored the data some, we'll introduce the Generalized +Linear Model and how to fit it with NeMoS. + +## Learning objectives {.keep-text} + +- Learn how to explore spiking data and do basic analyses using pynapple +- Learn how to structure data for NeMoS +- Learn how to fit a basic Generalized Linear Model using NeMoS +- Learn how to retrieve the parameters and predictions from a fit GLM for + intrepetation. + +```{code-cell} ipython3 +# Import everything +import jax +import matplotlib.pyplot as plt +import numpy as np +import pynapple as nap + +import nemos as nmo + +# some helper plotting functions +from nemos import _documentation_utils as doc_plots + +# configure plots some +plt.style.use(nmo.styles.plot_style) +``` + +## Data Streaming + +While you can download the data directly from the Allen Brain Atlas and +interact with it using their +[AllenSDK](https://allensdk.readthedocs.io/en/latest/visual_behavior_neuropixels.html), +we prefer the burgeoning [Neurodata Without Borders (NWB) +standard](https://nwb-overview.readthedocs.io/en/latest/). We have converted +this single dataset to NWB and uploaded it to the [Open Science +Framework](https://osf.io/5crqj/). This allows us to easily load the data +using pynapple, and it will immediately be in a format that pynapple understands! + +!!! tip + + Pynapple can stream any NWB-formatted dataset! See [their + documentation](https://pynapple.org/examples/tutorial_pynapple_dandi.html) + for more details, and see the [DANDI Archive](https://dandiarchive.org/) + for a repository of compliant datasets. + +The first time the following cell is run, it will take a little bit of time +to download the data, and a progress bar will show the download's progress. +On subsequent runs, the cell gets skipped: we do not need to redownload the +data. + + +```{code-cell} ipython3 +path = nmo.fetch.fetch_data("allen_478498617.nwb") +``` + +## Pynapple + +### Data structures and preparation + +Now that we've downloaded the data, let's open it with pynapple and examine +its contents. + + +```{code-cell} ipython3 +data = nap.load_file(path) +print(data) +``` + +The dataset contains several different pynapple objects, which we will +explore throughout this demo. The following illustrates how these fields relate to the data +we visualized above: + +![Annotated view of the data we will analyze.](../../assets/allen_data_annotated.gif) + + +- `units`: dictionary of neurons, holding each neuron's spike timestamps. +- `epochs`: start and end times of different intervals, defining the + experimental structure, specifying when each stimulation protocol began and + ended. +- `stimulus`: injected current, in Amperes, sampled at 20k Hz. +- `response`: the neuron's intracellular voltage, sampled at 20k Hz. + We will not use this info in this example + +Now let's go through the relevant variables in some more detail: + + +```{code-cell} ipython3 +trial_interval_set = data["epochs"] + +current = data["stimulus"] +spikes = data["units"] +``` + +First, let's examine `trial_interval_set`: + + +```{code-cell} ipython3 +trial_interval_set.keys() +``` + +`trial_interval_set` is a dictionary with strings for keys and +[`IntervalSets`](https://pynapple.org/generated/pynapple.core.interval_set.IntervalSet.html) +for values. Each key defines the stimulus protocol, with the value defining +the beginning and end of that stimulation protocol. + + +```{code-cell} ipython3 +noise_interval = trial_interval_set["Noise 1"] +noise_interval +``` + +As described above, we will be examining "Noise 1". We can see it contains +three rows, each defining a separate sweep. We'll just grab the first sweep +(shown in blue in the pictures above) and ignore the other two (shown in +gray). + + +```{code-cell} ipython3 +noise_interval = noise_interval[0] +noise_interval +``` + +Now let's examine `current`: + + +```{code-cell} ipython3 +current +``` + +`current` is a `Tsd` +([TimeSeriesData](https://pynapple.org/generated/pynapple.core.time_series.Tsd.html)) +object with 2 columns. Like all `Tsd` objects, the first column contains the +time index and the second column contains the data; in this case, the current +in Ampere (A). + +Currently, `current` contains the entire ~900 second experiment but, as +discussed above, we only want one of the "Noise 1" sweeps. Fortunately, +`pynapple` makes it easy to grab out the relevant time points by making use +of the `noise_interval` we defined above: + + +```{code-cell} ipython3 +current = current.restrict(noise_interval) +# convert current from Ampere to pico-amperes, to match the above visualization +# and move the values to a more reasonable range. +current = current * 1e12 +current +``` + +Notice that the timestamps have changed and our shape is much smaller. + +Finally, let's examine the spike times. `spikes` is a +[`TsGroup`](https://pynapple.org/generated/pynapple.core.ts_group.TsGroup.html#pynapple.core.ts_group.TsGroup), +a dictionary-like object that holds multiple `Ts` (timeseries) objects with +potentially different time indices: + + +```{code-cell} ipython3 +spikes +``` + +Typically, this is used to hold onto the spike times for a population of +neurons. In this experiment, we only have recordings from a single neuron, so +there's only one row. + +We can index into the `TsGroup` to see the timestamps for this neuron's +spikes: + + +```{code-cell} ipython3 +spikes[0] +``` + +Similar to `current`, this object originally contains data from the entire +experiment. To get only the data we need, we again use +`restrict(noise_interval)`: + + +```{code-cell} ipython3 +spikes = spikes.restrict(noise_interval) +print(spikes) +spikes[0] +``` + +Now, let's visualize the data from this trial, replicating rows 1 and 3 +from the Allen Brain Atlas figure at the beginning of this notebook: + + +```{code-cell} ipython3 +fig, ax = plt.subplots(1, 1, figsize=(8, 2)) +ax.plot(current, "grey") +ax.plot(spikes.to_tsd([-5]), "|", color="k", ms = 10) +ax.set_ylabel("Current (pA)") +ax.set_xlabel("Time (s)") +``` + +### Basic analyses + +Before using the Generalized Linear Model, or any model, it's worth taking +some time to examine our data and think about what features are interesting +and worth capturing. As we discussed in the [background](../../background/plot_00_conceptual_intro), +the GLM is a model of the neuronal firing rate. However, in our experiments, +we do not observe the firing rate, only the spikes! Moreover, neural +responses are typically noisy—even in this highly controlled experiment +where the same current was injected over multiple trials, the spike times +were slightly different from trial-to-trial. No model can perfectly predict +spike times on an individual trial, so how do we tell if our model is doing a +good job? + +Our objective function is the log-likelihood of the observed spikes given the +predicted firing rate. That is, we're trying to find the firing rate, as a +function of time, for which the observed spikes are likely. Intuitively, this +makes sense: the firing rate should be high where there are many spikes, and +vice versa. However, it can be difficult to figure out if your model is doing +a good job by squinting at the observed spikes and the predicted firing rates +plotted together. + +One common way to visualize a rough estimate of firing rate is to smooth +the spikes by convolving them with a Gaussian filter. + +!!! info + + This is a heuristic for getting the firing rate, and shouldn't be taken + as the literal truth (to see why, pass a firing rate through a Poisson + process to generate spikes and then smooth the output to approximate the + generating firing rate). A model should not be expected to match this + approximate firing rate exactly, but visualizing the two firing rates + together can help you reason about which phenomena in your data the model + is able to adequately capture, and which it is missing. + + For more information, see section 1.2 of [*Theoretical + Neuroscience*](https://boulderschool.yale.edu/sites/default/files/files/DayanAbbott.pdf), + by Dayan and Abbott. + +Pynapple can easily compute this approximate firing rate, and plotting this +information will help us pull out some phenomena that we think are +interesting and would like a model to capture. + +First, we must convert from our spike times to binned spikes: + + +```{code-cell} ipython3 +# bin size in seconds +bin_size = 0.001 +# Get spikes for neuron 0 +count = spikes[0].count(bin_size) +count +``` + +Now, let's convert the binned spikes into the firing rate, by smoothing them +with a gaussian kernel. Pynapple again provides a convenience function for +this: + + +```{code-cell} ipython3 +# the inputs to this function are the standard deviation of the gaussian in seconds and +# the full width of the window, in standard deviations. So std=.05 and size_factor=20 +# gives a total filter size of 0.05 sec * 20 = 1 sec. +firing_rate = count.smooth(std=0.05, size_factor=20) +# convert from spikes per bin to spikes per second (Hz) +firing_rate = firing_rate / bin_size +``` + +Note that firing_rate is a [`TsdFrame`](https://pynapple.org/generated/pynapple.core.time_series.TsdFrame.html)! + + + +```{code-cell} ipython3 +print(type(firing_rate)) +``` + +Now that we've done all this preparation, let's make a plot to more easily +visualize the data. + +!!! note + + We're hiding the details of the plotting function for the purposes of this + tutorial, but you can find it in [the source + code](https://github.com/flatironinstitute/nemos/blob/development/src/nemos/_documentation_utils/plotting.py) + if you are interested. + + +```{code-cell} ipython3 +doc_plots.current_injection_plot(current, spikes, firing_rate) +``` + +So now that we can view the details of our experiment a little more clearly, +what do we see? + +- We have three intervals of increasing current, and the firing rate + increases as the current does. + +- While the neuron is receiving the input, it does not fire continuously or + at a steady rate; there appears to be some periodicity in the response. The + neuron fires for a while, stops, and then starts again. There's periodicity + in the input as well, so this pattern in the response might be reflecting + that. + +- There's some decay in firing rate as the input remains on: there are three + four "bumps" of neuronal firing in the second and third intervals and they + decrease in amplitude, with first being the largest. + +These give us some good phenomena to try and predict! But there's something +that's not quite obvious from the above plot: what is the relationship +between the input and the firing rate? As described in the first bullet point +above, it looks to be *monotonically increasing*: as the current increases, +so does the firing rate. But is that exactly true? What form is that +relationship? + +Pynapple can compute a tuning curve to help us answer this question, by +binning our spikes based on the instantaneous input current and computing the +firing rate within those bins: + +!!! note "Tuning curve in `pynapple`" + [`compute_1d_tuning_curves`](https://pynapple.org/generated/pynapple.process.tuning_curves.html#pynapple.process.tuning_curves.compute_1d_tuning_curves) : compute the firing rate as a function of a 1-dimensional feature. + + +```{code-cell} ipython3 +tuning_curve = nap.compute_1d_tuning_curves(spikes, current, nb_bins=15) +tuning_curve +``` + +`tuning_curve` is a pandas DataFrame where each column is a neuron (one +neuron in this case) and each row is a bin over the feature (here, the input +current). We can easily plot the tuning curve of the neuron: + + +```{code-cell} ipython3 +doc_plots.tuning_curve_plot(tuning_curve) +``` + +We can see that, while the firing rate mostly increases with the current, +it's definitely not a linear relationship, and it might start decreasing as +the current gets too large. + +So this gives us three interesting phenomena we'd like our model to help +explain: the tuning curve between the firing rate and the current, the firing +rate's periodicity, and the gradual reduction in firing rate while the +current remains on. + + ++++ + +## NeMoS {.strip-code} + +### Preparing data + +Now that we understand our model, we're almost ready to put it together. +Before we construct it, however, we need to get the data into the right +format. + +NeMoS requires that the predictors and spike counts it operates on have the +following properties: + +- predictors and spike counts must have the same number of time points. + +- predictors must be two-dimensional, with shape `(n_time_bins, n_features)`. + In this example, we have a single feature (the injected current). + +- spike counts must be one-dimensional, with shape `(n_time_bins, )`. As + discussed above, `n_time_bins` must be the same for both the predictors and + spike counts. + +- predictors and spike counts must be + [`jax.numpy`](https://jax.readthedocs.io/en/latest/jax-101/01-jax-basics.html) + arrays, `numpy` arrays or `pynapple` `TsdFrame`/`Tsd`. + +!!! info "What is jax?" + + [jax](https://github.com/google/jax) is a Google-supported python library + for automatic differentiation. It has all sorts of neat features, but the + most relevant of which for NeMoS is its GPU-compatibility and + just-in-time compilation (both of which make code faster with little + overhead!), as well as the collection of optimizers present in + [jaxopt](https://jaxopt.github.io/stable/). + +First, we require that our predictors and our spike counts have the same +number of time bins. We can achieve this by down-sampling our current to the +spike counts to the proper resolution using the +[`bin_average`](https://pynapple.org/generated/pynapple.core.time_series.Tsd.bin_average.html#pynapple.core.time_series.Tsd.bin_average) +method from pynapple: + + +```{code-cell} ipython3 +binned_current = current.bin_average(bin_size) + +print(f"current shape: {binned_current.shape}") +# rate is in Hz, convert to KHz +print(f"current sampling rate: {binned_current.rate/1000.:.02f} KHz") + +print(f"\ncount shape: {count.shape}") +print(f"count sampling rate: {count.rate/1000:.02f} KHz") +``` + +Secondly, we have to reshape our variables so that they are the proper shape: + +- `predictors`: `(n_time_bins, n_features)` +- `count`: `(n_time_bins, )` + +Because we only have a single predictor feature, we'll use +[`np.expand_dims`](https://numpy.org/doc/stable/reference/generated/numpy.expand_dims.html) +to ensure it is a 2d array. + + +```{code-cell} ipython3 +predictor = np.expand_dims(binned_current, 1) + +# check that the dimensionality matches NeMoS expectation +print(f"predictor shape: {predictor.shape}") +print(f"count shape: {count.shape}") +``` + +!!! info "What if I have more than one neuron?" + + In this example, we're only fitting data for a single neuron, but you + might wonder how the data should be shaped if you have more than one + neuron -- do you add an extra dimension? or concatenate neurons along one + of the existing dimensions? + + In NeMoS, we always fit Generalized Linear Models to a single neuron at a + time. We'll discuss this more in the [following + tutorial](../plot_02_head_direction/), but briefly: you get the same answer + whether you fit the neurons separately or simultaneously, and fitting + them separately can make your life easier. + +### Fitting the model + +Now we're ready to fit our model! + +First, we need to define our GLM model object. We intend for users +to interact with our models like +[scikit-learn](https://scikit-learn.org/stable/getting_started.html) +estimators. In a nutshell, a model instance is initialized with +hyperparameters that specify optimization and model details, +and then the user calls the `.fit()` function to fit the model to data. +We will walk you through the process below by example, but if you +are interested in reading more details see the [Getting Started with scikit-learn](https://scikit-learn.org/stable/getting_started.html) webpage. + +To initialize our model, we need to specify the regularizer and observation +model objects, both of which should be one of our custom objects: + +- Regularizer: this object specifies both the solver algorithm and the + regularization scheme. They are jointly specified because each + regularization scheme has a list of compatible solvers to choose between. + Regularization modifies the objective function to reflect your prior + beliefs about the parameters, such as sparsity. Regularization becomes more + important as the number of input features, and thus model parameters, + grows. They can be found within `nemos.regularizer`. + +!!! warning + + With a convex problem like the GLM, in theory it does not matter which + solver algorithm you use. In practice, due to numerical issues, it + generally does. Thus, it's worth trying a couple to see how their + solutions compare. (Different regularization schemes will always give + different results.) + +- Observation model: this object links the firing rate and the observed + data (in this case spikes), describing the distribution of neural activity (and thus changing + the log-likelihood). For spiking data, we use the Poisson observation model, but + we discuss other options for continuous data + in [the calcium imaging analysis demo](../plot_06_calcium_imaging/). + +For this example, we'll use an un-regularized LBFGS solver. We'll discuss +regularization in a later tutorial. + +!!! info "Why LBFGS?" + + [LBFGS](https://en.wikipedia.org/wiki/Limited-memory_BFGS) is a + quasi-Netwon method, that is, it uses the first derivative (the gradient) + and approximates the second derivative (the Hessian) in order to solve + the problem. This means that LBFGS tends to find a solution faster and is + often less sensitive to step-size. Try other solvers to see how they + behave! + + + +```{code-cell} ipython3 +# Initialize the model w/regularizer and solver +model = nmo.glm.GLM(solver_name="LBFGS") +``` + +Now that we've initialized our model with the optimization parameters, we can +fit our data! In the previous section, we prepared our model matrix +(`predictor`) and target data (`count`), so to fit the model we just need to +pass them to the model: + + +```{code-cell} ipython3 +model.fit(predictor, count) +``` + +Now that we've fit our data, we can retrieve the resulting parameters. +Similar to scikit-learn, these are stored as the `coef_` and `intercept_` +attributes: + + +```{code-cell} ipython3 +print(f"firing_rate(t) = exp({model.coef_} * current(t) + {model.intercept_})") +``` + +Note that `model.coef_` has shape `(n_features, )`, while `model.intercept_` +is a scalar: + + +```{code-cell} ipython3 +print(f"coef_ shape: {model.coef_.shape}") +print(f"intercept_ shape: {model.intercept_.shape}") +``` + +It's nice to get the parameters above, but we can't tell how well our model +is doing by looking at them. So how should we evaluate our model? + +First, we can use the model to predict the firing rates and compare that to +the smoothed spike train. By calling `predict()` we can get the model's +predicted firing rate for this data. Note that this is just the output of the +model's linear-nonlinear step, as described earlier! + + +```{code-cell} ipython3 +# mkdocs_gallery_thumbnail_number = 4 + +predicted_fr = model.predict(predictor) +# convert units from spikes/bin to spikes/sec +predicted_fr = predicted_fr / bin_size + + +# and let's smooth the firing rate the same way that we smoothed the firing rate +smooth_predicted_fr = predicted_fr.smooth(0.05, size_factor=20) + +# and plot! +doc_plots.current_injection_plot(current, spikes, firing_rate, + # plot the predicted firing rate that has + # been smoothed the same way as the + # smoothed spike train + predicted_firing_rate=smooth_predicted_fr) +``` + +What do we see above? Note that the y-axes in the final row are different for +each subplot! + +- Predicted firing rate increases as injected current goes up — Success! :tada: + +- The amplitude of the predicted firing rate only matches the observed + amplitude in the third interval: it's too high in the first and too low in + the second — Failure! :x: + +- Our predicted firing rate has the periodicity we see in the smoothed spike + train — Success! :tada: + +- The predicted firing rate does not decay as the input remains on: the + amplitudes are identical for each of the bumps within a given interval — + Failure! :x: + +The failure described in the second point may seem particularly confusing — +approximate amplitude feels like it should be very easy to capture, so what's +going on? + +To get a better sense, let's look at the mean firing rate over the whole +period: + + +```{code-cell} ipython3 +# compare observed mean firing rate with the model predicted one +print(f"Observed mean firing rate: {np.mean(count) / bin_size} Hz") +print(f"Predicted mean firing rate: {np.mean(predicted_fr)} Hz") +``` + +We matched the average pretty well! So we've matched the average and the +range of inputs from the third interval reasonably well, but overshot at low +inputs and undershot in the middle. + +We can see this more directly by computing the tuning curve for our predicted +firing rate and comparing that against our smoothed spike train from the +beginning of this notebook. Pynapple can help us again with this: + + +```{code-cell} ipython3 +tuning_curve_model = nap.compute_1d_tuning_curves_continuous(predicted_fr[:, np.newaxis], current, 15) +fig = doc_plots.tuning_curve_plot(tuning_curve) +fig.axes[0].plot(tuning_curve_model, color="tomato", label="glm") +fig.axes[0].legend() +``` + +In addition to making that mismatch discussed earlier a little more obvious, +this tuning curve comparison also highlights that this model thinks the +firing rate will continue to grow as the injected current increases, which is +not reflected in the data. + +Viewing this plot also makes it clear that the model's tuning curve is +approximately exponential. We already knew that! That's what it means to be a +LNP model of a single input. But it's nice to see it made explicit. + +### Finishing up + +There are a handful of other operations you might like to do with the GLM. +First, you might be wondering how to simulate spikes — the GLM is a LNP +model, but the firing rate is just the output of *LN*, its first two steps. +The firing rate is just the mean of a Poisson process, so we can pass it to +`jax.random.poisson`: + + +```{code-cell} ipython3 +spikes = jax.random.poisson(jax.random.PRNGKey(123), predicted_fr.values) +``` + +Note that this is not actually that informative and, in general, it is +recommended that you focus on firing rates when interpreting your model. + +Also, while +including spike history is often helpful, it can sometimes make simulations unstable: +if your GLM includes auto-regressive inputs (e.g., neurons are +connected to themselves or each other), simulations can sometimes can behave +poorly because of runaway excitation [$^{[1, 2]}$](#ref-1). + +Finally, you may want a number with which to evaluate your model's +performance. As discussed earlier, the model optimizes log-likelihood to find +the best-fitting weights, and we can calculate this number using its `score` +method: + + +```{code-cell} ipython3 +log_likelihood = model.score(predictor, count, score_type="log-likelihood") +print(f"log-likelihood: {log_likelihood}") +``` + +This log-likelihood is un-normalized and thus doesn't mean that much by +itself, other than "higher=better". When comparing alternative GLMs fit on +the same dataset, whether that's models using different regularizers and +solvers or those using different predictors, comparing log-likelihoods is a +reasonable thing to do. + +!!! info + + Under the hood, NeMoS is minimizing the negative log-likelihood, as is + typical in many optimization contexts. `score` returns the real + log-likelihood, however, and thus higher is better. + +Because it's un-normalized, however, the log-likelihood should not be +compared across datasets (because e.g., it won't account for difference in +noise levels). We provide the ability to compute the pseudo-$R^2$ for this +purpose: + + +```{code-cell} ipython3 +model.score(predictor, count, score_type='pseudo-r2-Cohen') +``` + +## Citation + +The data used in this tutorial is from the **Allen Brain Map**, with the +[following +citation](https://knowledge.brain-map.org/data/1HEYEW7GMUKWIQW37BO/summary): + +**Contributors:** Agata Budzillo, Bosiljka Tasic, Brian R. Lee, Fahimeh +Baftizadeh, Gabe Murphy, Hongkui Zeng, Jim Berg, Nathan Gouwens, Rachel +Dalley, Staci A. Sorensen, Tim Jarsky, Uygar Sümbül Zizhen Yao + +**Dataset:** Allen Institute for Brain Science (2020). Allen Cell Types Database +-- Mouse Patch-seq [dataset]. Available from +brain-map.org/explore/classes/multimodal-characterization. + +**Primary publication:** Gouwens, N.W., Sorensen, S.A., et al. (2020). Integrated +morphoelectric and transcriptomic classification of cortical GABAergic cells. +Cell, 183(4), 935-953.E19. https://doi.org/10.1016/j.cell.2020.09.057 + +**Patch-seq protocol:** Lee, B. R., Budzillo, A., et al. (2021). Scaled, high +fidelity electrophysiological, morphological, and transcriptomic cell +characterization. eLife, 2021;10:e65482. https://doi.org/10.7554/eLife.65482 + +**Mouse VISp L2/3 glutamatergic neurons:** Berg, J., Sorensen, S. A., Miller, J., +Ting, J., et al. (2021) Human neocortical expansion involves glutamatergic +neuron diversification. Nature, 598(7879):151-158. doi: +10.1038/s41586-021-03813-8 + +## References + +[1] Arribas, Diego, Yuan Zhao, and Il Memming Park. "Rescuing neural spike train models from bad MLE." Advances in Neural Information Processing Systems 33 (2020): 2293-2303. + +[2] Hocker, David, and Memming Park. "Multistep inference for generalized linear spiking models curbs runaway excitation." International IEEE/EMBS Conference on Neural Engineering, May 2017. diff --git a/docs/tutorials/plot_02_head_direction.md b/docs/tutorials/plot_02_head_direction.md new file mode 100644 index 00000000..f1e10cb9 --- /dev/null +++ b/docs/tutorials/plot_02_head_direction.md @@ -0,0 +1,671 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +```{code-cell} ipython3 +%matplotlib inline +``` + + +# Fit head-direction population + +## Learning objectives + +- Learn how to add history-related predictors to NeMoS GLM +- Learn about NeMoS `Basis` objects +- Learn how to use `Basis` objects with convolution + +```{code-cell} ipython3 +import matplotlib.pyplot as plt +import numpy as np +import pynapple as nap + +import nemos as nmo + +# some helper plotting functions +from nemos import _documentation_utils as doc_plots + +# configure pynapple to ignore conversion warning +nap.nap_config.suppress_conversion_warnings = True + +# configure plots some +plt.style.use(nmo.styles.plot_style) +``` + +## Data Streaming + +Here we load the data from OSF. The data is a NWB file. + + +```{code-cell} ipython3 +path = nmo.fetch.fetch_data("Mouse32-140822.nwb") +``` + +## Pynapple +We are going to open the NWB file with pynapple. + + +```{code-cell} ipython3 +data = nap.load_file(path) + +data +``` + +Get spike timings + + +```{code-cell} ipython3 +spikes = data["units"] + +spikes +``` + +Get the behavioural epochs (in this case, sleep and wakefulness) + + + +```{code-cell} ipython3 +epochs = data["epochs"] +wake_ep = data["epochs"]["wake"] +``` + +Get the tracked orientation of the animal + + +```{code-cell} ipython3 +angle = data["ry"] +``` + +This cell will restrict the data to what we care about i.e. the activity of head-direction neurons during wakefulness. + + + +```{code-cell} ipython3 +spikes = spikes.getby_category("location")["adn"] + +spikes = spikes.restrict(wake_ep).getby_threshold("rate", 1.0) +angle = angle.restrict(wake_ep) +``` + +First let's check that they are head-direction neurons. + + +```{code-cell} ipython3 +tuning_curves = nap.compute_1d_tuning_curves( + group=spikes, feature=angle, nb_bins=61, minmax=(0, 2 * np.pi) +) +``` + +Each row indicates an angular bin (in radians), and each column corresponds to a single unit. +Let's plot the tuning curve of the first two neurons. + + +```{code-cell} ipython3 +fig, ax = plt.subplots(1, 2, figsize=(12, 4)) +ax[0].plot(tuning_curves.iloc[:, 0]) +ax[0].set_xlabel("Angle (rad)") +ax[0].set_ylabel("Firing rate (Hz)") +ax[1].plot(tuning_curves.iloc[:, 1]) +ax[1].set_xlabel("Angle (rad)") +plt.tight_layout() +``` + +Before using NeMoS, let's explore the data at the population level. + +Let's plot the preferred heading + + + +```{code-cell} ipython3 +fig = doc_plots.plot_head_direction_tuning( + tuning_curves, spikes, angle, threshold_hz=1, start=8910, end=8960 +) +``` + +As we can see, the population activity tracks very well the current head-direction of the animal. +**Question : are neurons constantly tuned to head-direction and can we use it to predict the spiking activity of each neuron based only on the activity of other neurons?** + +To fit the GLM faster, we will use only the first 3 min of wake + + +```{code-cell} ipython3 +wake_ep = nap.IntervalSet( + start=wake_ep.start[0], end=wake_ep.start[0] + 3 * 60 +) +``` + +To use the GLM, we need first to bin the spike trains. Here we use pynapple + + +```{code-cell} ipython3 +bin_size = 0.01 +count = spikes.count(bin_size, ep=wake_ep) +``` + +Here we are going to rearrange neurons order based on their prefered directions. + + + +```{code-cell} ipython3 +pref_ang = tuning_curves.idxmax() + +count = nap.TsdFrame( + t=count.t, + d=count.values[:, np.argsort(pref_ang.values)], +) +``` + +## NeMoS {.strip-code} +It's time to use NeMoS. Our goal is to estimate the pairwise interaction between neurons. +This can be quantified with a GLM if we use the recent population spike history to predict the current time step. +### Self-Connected Single Neuron +To simplify our life, let's see first how we can model spike history effects in a single neuron. +The simplest approach is to use counts in fixed length window $i$, $y_{t-i}, \dots, y_{t-1}$ to predict the next +count $y_{t}$. Let's plot the count history, + + + +```{code-cell} ipython3 +# select a neuron's spike count time series +neuron_count = count[:, 0] + +# restrict to a smaller time interval +epoch_one_spk = nap.IntervalSet( + start=count.time_support.start[0], end=count.time_support.start[0] + 1.2 +) +plt.figure(figsize=(8, 3.5)) +plt.step( + neuron_count.restrict(epoch_one_spk).t, neuron_count.restrict(epoch_one_spk).d, where="post" +) +plt.title("Spike Count Time Series") +plt.xlabel("Time (sec)") +plt.ylabel("Counts") +plt.tight_layout() +``` + +#### Features Construction +Let's fix the spike history window size that we will use as predictor. + + +```{code-cell} ipython3 +# set the size of the spike history window in seconds +window_size_sec = 0.8 + +doc_plots.plot_history_window(neuron_count, epoch_one_spk, window_size_sec) +``` + +For each time point, we shift our window one bin at the time and vertically stack the spike count history in a matrix. +Each row of the matrix will be used as the predictors for the rate in the next bin (red narrow rectangle in +the figure). + + +```{code-cell} ipython3 +doc_plots.run_animation(neuron_count, epoch_one_spk.start[0]) +``` + +If $t$ is smaller than the window size, we won't have a full window of spike history for estimating the rate. +One may think of padding the window (with zeros for example) but this may generate weird border artifacts. +To avoid that, we can simply restrict our analysis to times $t$ larger than the window and NaN-pad earlier +time-points; + +A fast way to compute this feature matrix is convolving the counts with the identity matrix. +We can apply the convolution and NaN-padding in a single step using the +[`nemos.convolve.create_convolutional_predictor`](../../../reference/nemos/convolve/#nemos.convolve.create_convolutional_predictor) +function. + + +```{code-cell} ipython3 +# convert the prediction window to bins (by multiplying with the sampling rate) +window_size = int(window_size_sec * neuron_count.rate) + +# convolve the counts with the identity matrix. +plt.close("all") +input_feature = nmo.convolve.create_convolutional_predictor( + np.eye(window_size), neuron_count +) + +# print the NaN indices along the time axis +print("NaN indices:\n", np.where(np.isnan(input_feature[:, 0]))[0]) +``` + +The binned counts originally have shape "number of samples", we should check that the +dimension are matching our expectation + + +```{code-cell} ipython3 +print(f"Time bins in counts: {neuron_count.shape[0]}") +print(f"Convolution window size in bins: {window_size}") +print(f"Feature shape: {input_feature.shape}") +``` + +We can visualize the output for a few time bins + + +```{code-cell} ipython3 +suptitle = "Input feature: Count History" +neuron_id = 0 +doc_plots.plot_features(input_feature, count.rate, suptitle) +``` + +As you may see, the time axis is backward, this happens because convolution flips the time axis. +This is equivalent, as we can interpret the result as how much a spike will affect the future rate. +In the previous tutorial our feature was 1-dimensional (just the current), now +instead the feature dimension is 80, because our bin size was 0.01 sec and the window size is 0.8 sec. +We can learn these weights by maximum likelihood by fitting a GLM. + + ++++ + +#### Fitting the Model + +When working a real dataset, it is good practice to train your models on a chunk of the data and +use the other chunk to assess the model performance. This process is known as "cross-validation". +There is no unique strategy on how to cross-validate your model; What works best +depends on the characteristic of your data (time series or independent samples, +presence or absence of trials...), and that of your model. Here, for simplicity use the first +half of the wake epochs for training and the second half for testing. This is a reasonable +choice if the statistics of the neural activity does not change during the course of +the recording. We will learn about better cross-validation strategies with other +examples. + + +```{code-cell} ipython3 +# construct the train and test epochs +duration = input_feature.time_support.tot_length("s") +start = input_feature.time_support["start"] +end = input_feature.time_support["end"] +first_half = nap.IntervalSet(start, start + duration / 2) +second_half = nap.IntervalSet(start + duration / 2, end) +``` + +Fit the glm to the first half of the recording and visualize the ML weights. + + +```{code-cell} ipython3 +# define the GLM object +model = nmo.glm.GLM(solver_name="LBFGS") + +# Fit over the training epochs +model.fit( + input_feature.restrict(first_half), + neuron_count.restrict(first_half) +) +``` + +```{code-cell} ipython3 +plt.figure() +plt.title("Spike History Weights") +plt.plot(np.arange(window_size) / count.rate, np.squeeze(model.coef_), lw=2, label="GLM raw history 1st Half") +plt.axhline(0, color="k", lw=0.5) +plt.xlabel("Time From Spike (sec)") +plt.ylabel("Kernel") +plt.legend() +``` + +The response in the previous figure seems noise added to a decay, therefore the response +can be described with fewer degrees of freedom. In other words, it looks like we +are using way too many weights to describe a simple response. +If we are correct, what would happen if we re-fit the weights on the other half of the data? +#### Inspecting the results + + +```{code-cell} ipython3 +# fit on the test set + +model_second_half = nmo.glm.GLM(solver_name="LBFGS") +model_second_half.fit( + input_feature.restrict(second_half), + neuron_count.restrict(second_half) +) + +plt.figure() +plt.title("Spike History Weights") +plt.plot(np.arange(window_size) / count.rate, np.squeeze(model.coef_), + label="GLM raw history 1st Half", lw=2) +plt.plot(np.arange(window_size) / count.rate, np.squeeze(model_second_half.coef_), + color="orange", label="GLM raw history 2nd Half", lw=2) +plt.axhline(0, color="k", lw=0.5) +plt.xlabel("Time From Spike (sec)") +plt.ylabel("Kernel") +plt.legend() +``` + +What can we conclude? + +The fast fluctuations are inconsistent across fits, indicating that +they are probably capturing noise, a phenomenon known as over-fitting; +On the other hand, the decaying trend is fairly consistent, even if +our estimate is noisy. You can imagine how things could get +worst if we needed a finer temporal resolution, such 1ms time bins +(which would require 800 coefficients instead of 80). +What can we do to mitigate over-fitting now? + +#### Reducing feature dimensionality +One way to proceed is to find a lower-dimensional representation of the response +by parametrizing the decay effect. For instance, we could try to model it +with an exponentially decaying function $f(t) = \exp( - \alpha t)$, with +$\alpha >0$ a positive scalar. This is not a bad idea, because we would greatly +simplify the dimensionality our features (from 80 to 1). Unfortunately, +there is no way to know a-priori what is a good parameterization. More +importantly, not all the parametrizations guarantee a unique and stable solution +to the maximum likelihood estimation of the coefficients (convexity). + +In the GLM framework, the main way to construct a lower dimensional parametrization +while preserving convexity, is to use a set of basis functions. +For history-type inputs, whether of the spiking history or of the current +history, we'll use the raised cosine log-stretched basis first described in +[Pillow et al., 2005](https://www.jneurosci.org/content/25/47/11003). This +basis set has the nice property that their precision drops linearly with +distance from event, which is a makes sense for many history-related inputs +in neuroscience: whether an input happened 1 or 5 msec ago matters a lot, +whereas whether an input happened 51 or 55 msec ago is less important. + + +```{code-cell} ipython3 +doc_plots.plot_basis() +``` + +!!! info + + We provide a handful of different choices for basis functions, and + selecting the proper basis function for your input is an important + analytical step. We will eventually provide guidance on this choice, but + for now we'll give you a decent choice. + +NeMoS includes `Basis` objects to handle the construction and use of these +basis functions. + +When we instantiate this object, the only arguments we need to specify is the +number of functions we want, the mode of operation of the basis (`"conv"`), +and the window size for the convolution. With more basis functions, we'll be able to +represent the effect of the corresponding input with the higher precision, at +the cost of adding additional parameters. + + +```{code-cell} ipython3 +# a basis object can be instantiated in "conv" mode for convolving the input. +basis = nmo.basis.RaisedCosineBasisLog( + n_basis_funcs=8, mode="conv", window_size=window_size +) + +# `basis.evaluate_on_grid` is a convenience method to view all basis functions +# across their whole domain: +time, basis_kernels = basis.evaluate_on_grid(window_size) + +print(basis_kernels.shape) + +# time takes equi-spaced values between 0 and 1, we could multiply by the +# duration of our window to scale it to seconds. +time *= window_size_sec +``` + +To appreciate why the raised-cosine basis can approximate well our response +we can learn a "good" set of weight for the basis element such that +a weighted sum of the basis approximates the GLM weights for the count history. +One way to do so is by minimizing the least-squares. + + +```{code-cell} ipython3 +# compute the least-squares weights +lsq_coef, _, _, _ = np.linalg.lstsq(basis_kernels, np.squeeze(model.coef_), rcond=-1) + +# plot the basis and the approximation +doc_plots.plot_weighted_sum_basis(time, model.coef_, basis_kernels, lsq_coef) +``` + +The first plot is the response of each of the 8 basis functions to a single +pulse. This is known as the impulse response function, and is a useful way to +characterize linear systems like our basis objects. The second plot are is a +bar plot representing the least-square coefficients. The third one are the +impulse responses scaled by the weights. The last plot shows the sum of the +scaled response overlapped to the original spike count history weights. + +Our predictor previously was huge: every possible 80 time point chunk of the +data, for 1440000 total numbers. By using this basis set we can instead reduce +the predictor to 8 numbers for every 80 time point window for 144000 total +numbers. Basically an order of magnitude less. With 1ms bins we would have +achieved 2 order of magnitude reduction in input size. This is a huge benefit +in terms of memory allocation and, computing time. As an additional benefit, +we will reduce over-fitting. + +Let's see our basis in action. We can "compress" spike history feature by convolving the basis +with the counts (without creating the large spike history feature matrix). +This can be performed in NeMoS by calling the "compute_features" method of basis. + + +```{code-cell} ipython3 +# equivalent to +# `nmo.convolve.create_convolutional_predictor(basis_kernels, neuron_count)` +conv_spk = basis.compute_features(neuron_count) + +print(f"Raw count history as feature: {input_feature.shape}") +print(f"Compressed count history as feature: {conv_spk.shape}") + +# Visualize the convolution results +epoch_one_spk = nap.IntervalSet(8917.5, 8918.5) +epoch_multi_spk = nap.IntervalSet(8979.2, 8980.2) + +doc_plots.plot_convolved_counts(neuron_count, conv_spk, epoch_one_spk, epoch_multi_spk) + +# find interval with two spikes to show the accumulation, in a second row +``` + +Now that we have our "compressed" history feature matrix, we can fit the ML parameters for a GLM. + + ++++ + +#### Fit and compare the models + + +```{code-cell} ipython3 +# use restrict on interval set training +model_basis = nmo.glm.GLM(solver_name="LBFGS") +model_basis.fit(conv_spk.restrict(first_half), neuron_count.restrict(first_half)) +``` + +We can plot the resulting response, noting that the weights we just learned needs to be "expanded" back +to the original `window_size` dimension by multiplying them with the basis kernels. +We have now 8 coefficients, + + +```{code-cell} ipython3 +print(model_basis.coef_) +``` + +In order to get the response we need to multiply the coefficients by their corresponding +basis function, and sum them. + + +```{code-cell} ipython3 +self_connection = np.matmul(basis_kernels, np.squeeze(model_basis.coef_)) + +print(self_connection.shape) +``` + +We can now compare this model that based on the raw count history. + + +```{code-cell} ipython3 +plt.figure() +plt.title("Spike History Weights") +plt.plot(time, np.squeeze(model.coef_), alpha=0.3, label="GLM raw history") +plt.plot(time, self_connection, "--k", label="GLM basis", lw=2) +plt.axhline(0, color="k", lw=0.5) +plt.xlabel("Time from spike (sec)") +plt.ylabel("Weight") +plt.legend() +``` + +Let's check if our new estimate does a better job in terms of over-fitting. We can do that +by visual comparison, as we did previously. Let's fit the second half of the dataset. + + +```{code-cell} ipython3 +model_basis_second_half = nmo.glm.GLM(solver_name="LBFGS") +model_basis_second_half.fit(conv_spk.restrict(second_half), neuron_count.restrict(second_half)) + +# compute responses for the 2nd half fit +self_connection_second_half = np.matmul(basis_kernels, np.squeeze(model_basis_second_half.coef_)) + +plt.figure() +plt.title("Spike History Weights") +plt.plot(time, np.squeeze(model.coef_), "k", alpha=0.3, label="GLM raw history 1st half") +plt.plot(time, np.squeeze(model_second_half.coef_), alpha=0.3, color="orange", label="GLM raw history 2nd half") +plt.plot(time, self_connection, "--k", lw=2, label="GLM basis 1st half") +plt.plot(time, self_connection_second_half, color="orange", lw=2, ls="--", label="GLM basis 2nd half") +plt.axhline(0, color="k", lw=0.5) +plt.xlabel("Time from spike (sec)") +plt.ylabel("Weight") +plt.legend() +``` + +Or we can score the model predictions using both one half of the set for training +and the other half for testing. + + +```{code-cell} ipython3 +# compare model scores, as expected the training score is better with more parameters +# this may could be over-fitting. +print(f"full history train score: {model.score(input_feature.restrict(first_half), neuron_count.restrict(first_half), score_type='pseudo-r2-Cohen')}") +print(f"basis train score: {model_basis.score(conv_spk.restrict(first_half), neuron_count.restrict(first_half), score_type='pseudo-r2-Cohen')}") +``` + +To check that, let's try to see ho the model perform on unseen data and obtaining a test +score. + + +```{code-cell} ipython3 +print(f"\nfull history test score: {model.score(input_feature.restrict(second_half), neuron_count.restrict(second_half), score_type='pseudo-r2-Cohen')}") +print(f"basis test score: {model_basis.score(conv_spk.restrict(second_half), neuron_count.restrict(second_half), score_type='pseudo-r2-Cohen')}") +``` + +Let's extract and plot the rates + + +```{code-cell} ipython3 +rate_basis = model_basis.predict(conv_spk) * conv_spk.rate +rate_history = model.predict(input_feature) * conv_spk.rate +ep = nap.IntervalSet(start=8819.4, end=8821) + +# plot the rates +doc_plots.plot_rates_and_smoothed_counts( + neuron_count, + {"Self-connection raw history":rate_history, "Self-connection bsais": rate_basis} +) +``` + +### All-to-all Connectivity +The same approach can be applied to the whole population. Now the firing rate of a neuron +is predicted not only by its own count history, but also by the rest of the +simultaneously recorded population. We can convolve the basis with the counts of each neuron +to get an array of predictors of shape, `(num_time_points, num_neurons * num_basis_funcs)`. + +#### Preparing the features + + +```{code-cell} ipython3 +# convolve all the neurons +convolved_count = basis.compute_features(count) +``` + +Check the dimension to make sure it make sense +Shape should be (n_samples, n_basis_func * n_neurons) + + +```{code-cell} ipython3 +print(f"Convolved count shape: {convolved_count.shape}") +``` + +#### Fitting the Model +This is an all-to-all neurons model. +We are using the class `PopulationGLM` to fit the whole population at once. + +!!! note + Once we condition on past activity, log-likelihood of the population is the sum of the log-likelihood + of individual neurons. Maximizing the sum (i.e. the population log-likelihood) is equivalent to + maximizing each individual term separately (i.e. fitting one neuron at the time). + + + +```{code-cell} ipython3 +model = nmo.glm.PopulationGLM( + regularizer="Ridge", + solver_name="LBFGS", + regularizer_strength=0.1 + ).fit(convolved_count, count) +``` + +#### Comparing model predictions. +Predict the rate (counts are already sorted by tuning prefs) + + +```{code-cell} ipython3 +predicted_firing_rate = model.predict(convolved_count) * conv_spk.rate +``` + +Plot fit predictions over a short window not used for training. + + +```{code-cell} ipython3 +# use pynapple for time axis for all variables plotted for tick labels in imshow +doc_plots.plot_head_direction_tuning_model(tuning_curves, predicted_firing_rate, spikes, angle, threshold_hz=1, + start=8910, end=8960, cmap_label="hsv") +``` + +Let's see if our firing rate predictions improved and in what sense. + + +```{code-cell} ipython3 +# mkdocs_gallery_thumbnail_number = 2 +doc_plots.plot_rates_and_smoothed_counts( + neuron_count, + {"Self-connection: raw history": rate_history, + "Self-connection: bsais": rate_basis, + "All-to-all: basis": predicted_firing_rate[:, 0]} +) +``` + +#### Visualizing the connectivity +Compute the tuning curve form the predicted rates. + + +```{code-cell} ipython3 +tuning = nap.compute_1d_tuning_curves_continuous(predicted_firing_rate, + feature=angle, + nb_bins=61, + minmax=(0, 2 * np.pi)) +``` + +Extract the weights and store it in a (n_neurons, n_neurons, n_basis_funcs) array. + + +```{code-cell} ipython3 +weights = model.coef_.reshape(count.shape[1], basis.n_basis_funcs, count.shape[1]) +``` + +Multiply the weights by the basis, to get the history filters. + + +```{code-cell} ipython3 +responses = np.einsum("jki,tk->ijt", weights, basis_kernels) + +print(responses.shape) +``` + +Finally, we can visualize the pairwise interactions by plotting +all the coupling filters. + + +```{code-cell} ipython3 +doc_plots.plot_coupling(responses, tuning) +``` diff --git a/docs/tutorials/plot_03_grid_cells.md b/docs/tutorials/plot_03_grid_cells.md new file mode 100644 index 00000000..c46ecd6a --- /dev/null +++ b/docs/tutorials/plot_03_grid_cells.md @@ -0,0 +1,305 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +```{code-cell} ipython3 +%matplotlib inline +``` + + +# Fit grid cell + +```{code-cell} ipython3 +import matplotlib.pyplot as plt +import numpy as np +import pynapple as nap +from scipy.ndimage import gaussian_filter + +import nemos as nmo +``` + +## Data Streaming + +Here we load the data from OSF. The data is a NWB file. + + +```{code-cell} ipython3 +io = nmo.fetch.download_dandi_data( + "000582", + "sub-11265/sub-11265_ses-07020602_behavior+ecephys.nwb", +) +``` + +## Pynapple + +Let's load the dataset and see what's inside + + +```{code-cell} ipython3 +dataset = nap.NWBFile(io.read(), lazy_loading=False) + +print(dataset) +``` + +In this case, the data were used in this [publication](https://www.science.org/doi/full/10.1126/science.1125572). +We thus expect to find neurons tuned to position and head-direction of the animal. +Let's verify that with pynapple. +First, extract the spike times and the position of the animal. + + +```{code-cell} ipython3 +spikes = dataset["units"] # Get spike timings +position = dataset["SpatialSeriesLED1"] # Get the tracked orientation of the animal +``` + +Here we compute quickly the head-direction of the animal from the position of the LEDs. + + +```{code-cell} ipython3 +diff = dataset["SpatialSeriesLED1"].values - dataset["SpatialSeriesLED2"].values +head_dir = (np.arctan2(*diff.T) + (2 * np.pi)) % (2 * np.pi) +head_dir = nap.Tsd(dataset["SpatialSeriesLED1"].index, head_dir).dropna() +``` + +Let's quickly compute some tuning curves for head-direction and spatial position. + + +```{code-cell} ipython3 +hd_tuning = nap.compute_1d_tuning_curves( + group=spikes, feature=head_dir, nb_bins=61, minmax=(0, 2 * np.pi) +) + +pos_tuning, binsxy = nap.compute_2d_tuning_curves( + group=spikes, features=position, nb_bins=12 +) +``` + +Let's plot the tuning curves for each neuron. + + +```{code-cell} ipython3 +fig = plt.figure(figsize=(12, 4)) +gs = plt.GridSpec(2, len(spikes)) +for i in range(len(spikes)): + ax = plt.subplot(gs[0, i], projection="polar") + ax.plot(hd_tuning.loc[:, i]) + + ax = plt.subplot(gs[1, i]) + ax.imshow(gaussian_filter(pos_tuning[i], sigma=1)) +plt.tight_layout() +``` + +## NeMoS +It's time to use NeMoS. +Let's try to predict the spikes as a function of position and see if we can generate better tuning curves +First we start by binning the spike trains in 10 ms bins. + + +```{code-cell} ipython3 +bin_size = 0.01 # second +counts = spikes.count(bin_size, ep=position.time_support) +``` + +We need to interpolate the position to the same time resolution. +We can still use pynapple for this. + + +```{code-cell} ipython3 +position = position.interpolate(counts) +``` + +We can define a two-dimensional basis for position by multiplying two one-dimensional bases, +see [here](../../background/plot_02_ND_basis_function) for more details. + + +```{code-cell} ipython3 +basis_2d = nmo.basis.RaisedCosineBasisLinear( + n_basis_funcs=10 +) * nmo.basis.RaisedCosineBasisLinear(n_basis_funcs=10) +``` + +Let's see what a few basis look like. Here we evaluate it on a 100 x 100 grid. + + +```{code-cell} ipython3 +X, Y, Z = basis_2d.evaluate_on_grid(100, 100) +``` + +We can visualize the basis. + + +```{code-cell} ipython3 +fig, axs = plt.subplots(2, 5, figsize=(10, 4)) +for k in range(2): + for h in range(5): + axs[k][h].contourf(X, Y, Z[:, :, 50 + 2 * (k + h)], cmap="Blues") + +plt.tight_layout() +``` + +Each basis element represent a possible position of the animal in an arena. +Now we can "evaluate" the basis for each position of the animal + + +```{code-cell} ipython3 +position_basis = basis_2d(position["x"], position["y"]) +``` + +Now try to make sense of what it is + + +```{code-cell} ipython3 +print(position_basis.shape) +``` + +The shape is (n_samples, n_basis). This means that for each time point "t", we evaluated the basis at the +corresponding position. Let's plot 5 time steps. + + +```{code-cell} ipython3 +fig = plt.figure(figsize=(12, 4)) +gs = plt.GridSpec(2, 5) +xt = np.arange(0, 1000, 200) +cmap = plt.get_cmap("rainbow") +colors = np.linspace(0, 1, len(xt)) +for cnt, i in enumerate(xt): + ax = plt.subplot(gs[0, i // 200]) + ax.imshow(position_basis[i].reshape(10, 10).T, origin="lower") + for spine in ["top", "bottom", "left", "right"]: + ax.spines[spine].set_color(cmap(colors[cnt])) + ax.spines[spine].set_linewidth(3) + plt.title("T " + str(i)) + +ax = plt.subplot(gs[1, 2]) + +ax.plot(position["x"][0:1000], position["y"][0:1000]) +for i in range(len(xt)): + ax.plot(position["x"][xt[i]], position["y"][xt[i]], "o", color=cmap(colors[i])) + +plt.tight_layout() +``` + +Now we can fit the GLM and see what we get. In this case, we use Ridge for regularization. +Here we will focus on the last neuron (neuron 7) who has a nice grid pattern + + +```{code-cell} ipython3 +model = nmo.glm.GLM( + regularizer="Ridge", + regularizer_strength=0.001 +) +``` + +Let's fit the model + + +```{code-cell} ipython3 +neuron = 7 + +model.fit(position_basis, counts[:, neuron]) +``` + +We can compute the model predicted firing rate. + + +```{code-cell} ipython3 +rate_pos = model.predict(position_basis) +``` + +And compute the tuning curves/ + + +```{code-cell} ipython3 +model_tuning, binsxy = nap.compute_2d_tuning_curves_continuous( + tsdframe=rate_pos[:, np.newaxis] * rate_pos.rate, features=position, nb_bins=12 +) +``` + +Let's compare the tuning curve predicted by the model with that based on the actual spikes. + + +```{code-cell} ipython3 +smooth_pos_tuning = gaussian_filter(pos_tuning[neuron], sigma=1) +smooth_model = gaussian_filter(model_tuning[0], sigma=1) + +vmin = min(smooth_pos_tuning.min(), smooth_model.min()) +vmax = max(smooth_pos_tuning.max(), smooth_model.max()) + +fig = plt.figure(figsize=(12, 4)) +gs = plt.GridSpec(1, 2) +ax = plt.subplot(gs[0, 0]) +ax.imshow(smooth_pos_tuning, vmin=vmin, vmax=vmax) +ax = plt.subplot(gs[0, 1]) +ax.imshow(smooth_model, vmin=vmin, vmax=vmax) +plt.tight_layout() +``` + +The grid shows but the peak firing rate is off, we might have over-regularized. +We can fix this by tuning the regularization strength by means of cross-validation. +This can be done through scikit-learn. Let's apply a grid-search over different +values, and select the regularization by k-fold cross-validation. + + +```{code-cell} ipython3 +# import the grid-search cross-validation from scikit-learn +from sklearn.model_selection import GridSearchCV + +# define the regularization strength that we want cross-validate +param_grid = dict(regularizer_strength=[1e-6, 1e-5, 1e-3]) + +# pass the model and the grid +cls = GridSearchCV(model, param_grid=param_grid) + +# run the search, the default is a 5-fold cross-validation strategy +cls.fit(position_basis, counts[:, neuron]) +``` + +Let's get the best estimator and see what we get. + + +```{code-cell} ipython3 +best_model = cls.best_estimator_ +``` + +Let's predict and compute the tuning curves once again. + + +```{code-cell} ipython3 +# predict the rate with the selected model +best_rate_pos = best_model.predict(position_basis) + +# compute the 2D tuning +best_model_tuning, binsxy = nap.compute_2d_tuning_curves_continuous( + tsdframe=best_rate_pos[:, np.newaxis] * best_rate_pos.rate, features=position, nb_bins=12 +) +``` + +We can now plot the results. + + +```{code-cell} ipython3 +# plot the resutls +smooth_best_model = gaussian_filter(best_model_tuning[0], sigma=1) + +vmin = min(smooth_pos_tuning.min(), smooth_model.min(), smooth_best_model.min()) +vmax = max(smooth_pos_tuning.max(), smooth_model.max(), smooth_best_model.max()) + +fig, axs = plt.subplots(1, 3, figsize=(12, 4)) +plt.suptitle("Rate predictions\n") +axs[0].set_title("Raw Counts") +axs[0].imshow(smooth_pos_tuning, vmin=vmin, vmax=vmax) +axs[1].set_title(f"Ridge - strength: {model.regularizer_strength}") +axs[1].imshow(smooth_model, vmin=vmin, vmax=vmax) +axs[2].set_title(f"Ridge - strength: {best_model.regularizer_strength}") +axs[2].imshow(smooth_best_model, vmin=vmin, vmax=vmax) +plt.tight_layout() +``` diff --git a/docs/tutorials/plot_04_v1_cells.md b/docs/tutorials/plot_04_v1_cells.md new file mode 100644 index 00000000..8a55c83d --- /dev/null +++ b/docs/tutorials/plot_04_v1_cells.md @@ -0,0 +1,334 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +```{code-cell} ipython3 +%matplotlib inline +``` + +# Fit V1 cell + +The data presented in this notebook was collected by [Sonica Saraf](https://www.cns.nyu.edu/~saraf/) from the [Movshon lab](https://www.cns.nyu.edu/labs/movshonlab/) at NYU. + +The notebook focuses on fitting a V1 cell model. + +```{code-cell} ipython3 +import matplotlib.pyplot as plt +import numpy as np +import pynapple as nap + +import nemos as nmo + +# configure plots some +plt.style.use(nmo.styles.plot_style) + + +# utility for filling a time series +def fill_forward(time_series, data, ep=None, out_of_range=np.nan): + """ + Fill a time series forward in time with data. + + Parameters + ---------- + time_series: + The time series to match. + data: Tsd, TsdFrame, or TsdTensor + The time series with data to be extend. + + Returns + ------- + : Tsd, TsdFrame, or TsdTensor + The data time series filled forward. + + """ + assert isinstance(data, (nap.Tsd, nap.TsdFrame, nap.TsdTensor)) + + if ep is None: + ep = time_series.time_support + else: + assert isinstance(ep, nap.IntervalSet) + time_series.restrict(ep) + + data = data.restrict(ep) + starts = ep.start + ends = ep.end + + filled_d = np.full((time_series.t.shape[0], *data.shape[1:]), out_of_range, dtype=data.dtype) + fill_idx = 0 + for start, end in zip(starts, ends): + data_ep = data.get(start, end) + ts_ep = time_series.get(start, end) + idxs = np.searchsorted(data_ep.t, ts_ep.t, side="right") - 1 + filled_d[fill_idx:fill_idx + ts_ep.t.shape[0]][idxs >= 0] = data_ep.d[idxs[idxs>=0]] + fill_idx += ts_ep.t.shape[0] + return type(data)(t=time_series.t, d=filled_d, time_support=ep) +``` + +## Data Streaming + + + +```{code-cell} ipython3 +path = nmo.fetch.fetch_data("m691l1.nwb") +``` + +## Pynapple +The data have been copied to your local station. +We are gonna open the NWB file with pynapple + + +```{code-cell} ipython3 +dataset = nap.load_file(path) +``` + +What does it look like? + + +```{code-cell} ipython3 +print(dataset) +``` + +Let's extract the data. + + +```{code-cell} ipython3 +epochs = dataset["epochs"] +units = dataset["units"] +stimulus = dataset["whitenoise"] +``` + +Stimulus is white noise shown at 40 Hz + + +```{code-cell} ipython3 +fig, ax = plt.subplots(1, 1, figsize=(12,4)) +ax.imshow(stimulus[0], cmap='Greys_r') +stimulus.shape +``` + +There are 73 neurons recorded together in V1. To fit the GLM faster, we will focus on one neuron. + + +```{code-cell} ipython3 +print(units) +# this returns TsGroup with one neuron only +spikes = units[[34]] +``` + +How could we predict neuron's response to white noise stimulus? + +- we could fit the instantaneous spatial response. that is, just predict + neuron's response to a given frame of white noise. this will give an x by y + filter. implicitly assumes that there's no temporal info: only matters what + we've just seen + +- could fit spatiotemporal filter. instead of an x by y that we use + independently on each frame, fit (x, y, t) over, say 100 msecs. and then + fit each of these independently (like in head direction example) + +- that's a lot of parameters! can simplify by assumping that the response is + separable: fit a single (x, y) filter and then modulate it over time. this + wouldn't catch e.g., direction-selectivity because it assumes that phase + preference is constant over time + +- could make use of our knowledge of V1 and try to fit a more complex + functional form, e.g., a Gabor. + +That last one is very non-linear and thus non-convex. we'll do the third one. + +in this example, we'll fit the spatial filter outside of the GLM framework, +using spike-triggered average, and then we'll use the GLM to fit the temporal +timecourse. + +## Spike-triggered average + +Spike-triggered average says: every time our neuron spikes, we store the +stimulus that was on the screen. for the whole recording, we'll have many of +these, which we then average to get this STA, which is the "optimal stimulus" +/ spatial filter. + +In practice, we do not just the stimulus on screen, but in some window of +time around it. (it takes some time for info to travel through the eye/LGN to +V1). Pynapple makes this easy: + + +```{code-cell} ipython3 +sta = nap.compute_event_trigger_average(spikes, stimulus, binsize=0.025, + windowsize=(-0.15, 0.0)) +``` + +sta is a `TsdTensor`, which gives us the 2d receptive field at each of the +time points. + + +```{code-cell} ipython3 +sta +``` + +We index into this in a 2d manner: row, column (here we only have 1 column). + + +```{code-cell} ipython3 +sta[1, 0] +``` + +we can easily plot this + + +```{code-cell} ipython3 +fig, axes = plt.subplots(1, len(sta), figsize=(3*len(sta),3)) +for i, t in enumerate(sta.t): + axes[i].imshow(sta[i,0], vmin = np.min(sta), vmax = np.max(sta), + cmap='Greys_r') + axes[i].set_title(str(t)+" s") +``` + +that looks pretty reasonable for a V1 simple cell: localized in space, +orientation, and spatial frequency. that is, looks Gabor-ish + +To convert this to the spatial filter we'll use for the GLM, let's take the +average across the bins that look informative: -.125 to -.05 + + +```{code-cell} ipython3 +# mkdocs_gallery_thumbnail_number = 3 +receptive_field = np.mean(sta.get(-0.125, -0.05), axis=0)[0] + +fig, ax = plt.subplots(1, 1, figsize=(4,4)) +ax.imshow(receptive_field, cmap='Greys_r') +``` + +This receptive field gives us the spatial part of the linear response: it +gives a map of weights that we use for a weighted sum on an image. There are +multiple ways of performing this operation: + + +```{code-cell} ipython3 +# element-wise multiplication and sum +print((receptive_field * stimulus[0]).sum()) +# dot product of flattened versions +print(np.dot(receptive_field.flatten(), stimulus[0].flatten())) +``` + +When performing this operation on multiple stimuli, things become slightly +more complicated. For loops on the above methods would work, but would be +slow. Reshaping and using the dot product is one common method, as are +methods like `np.tensordot`. + +We'll use einsum to do this, which is a convenient way of representing many +different matrix operations: + + +```{code-cell} ipython3 +filtered_stimulus = np.einsum('t h w, h w -> t', stimulus, receptive_field) +``` + +This notation says: take these arrays with dimensions `(t,h,w)` and `(h,w)` +and multiply and sum to get an array of shape `(t,)`. This performs the same +operations as above. + +And this remains a pynapple object, so we can easily visualize it! + + +```{code-cell} ipython3 +fig, ax = plt.subplots(1, 1, figsize=(12,4)) +ax.plot(filtered_stimulus) +``` + +But what is this? It's how much each frame in the video should drive our +neuron, based on the receptive field we fit using the spike-triggered +average. + +This, then, is the spatial component of our input, as described above. + +## Preparing data for NeMoS + +We'll now use the GLM to fit the temporal component. To do that, let's get +this and our spike counts into the proper format for NeMoS: + + +```{code-cell} ipython3 +# grab spikes from when we were showing our stimulus, and bin at 1 msec +# resolution +bin_size = .001 +counts = spikes[34].restrict(filtered_stimulus.time_support).count(bin_size) +print(counts.rate) +print(filtered_stimulus.rate) +``` + +Hold on, our stimulus is at a much lower rate than what we want for our rates +-- in previous tutorials, our input has been at a higher rate than our spikes, +and so we used `bin_average` to down-sample to the appropriate rate. When the +input is at a lower rate, we need to think a little more carefully about how +to up-sample. + + +```{code-cell} ipython3 +print(counts[:5]) +print(filtered_stimulus[:5]) +``` + +What was the visual input to the neuron at time 0.005? It was the same input +as time 0. At time 0.0015? Same thing, up until we pass time 0.025017. Thus, +we want to "fill forward" the values of our input, and we have pynapple +convenience function to do so: + + +```{code-cell} ipython3 +filtered_stimulus = fill_forward(counts, filtered_stimulus) +filtered_stimulus +``` + +We can see that the time points are now aligned, and we've filled forward the +values the way we'd like. + +Now, similar to the [head direction tutorial](../plot_02_head_direction), we'll +use the log-stretched raised cosine basis to create the predictor for our +GLM: + + +```{code-cell} ipython3 +window_size = 100 +basis = nmo.basis.RaisedCosineBasisLog(8, mode="conv", window_size=window_size) + +convolved_input = basis.compute_features(filtered_stimulus) +``` + +convolved_input has shape (n_time_pts, n_features * n_basis_funcs), because +n_features is the singleton dimension from filtered_stimulus. + +## Fitting the GLM + +Now we're ready to fit the model! Let's do it, same as before: + + +```{code-cell} ipython3 +model = nmo.glm.GLM() +model.fit(convolved_input, counts) +``` + +We have our coefficients for each of our 8 basis functions, let's combine +them to get the temporal time course of our input: + + +```{code-cell} ipython3 +time, basis_kernels = basis.evaluate_on_grid(window_size) +time *= bin_size * window_size +temp_weights = np.einsum('b, t b -> t', model.coef_, basis_kernels) +plt.plot(time, temp_weights) +plt.xlabel("time[sec]") +plt.ylabel("amplitude") +``` + +When taken together, the results of the GLM and the spike-triggered average +give us the linear component of our LNP model: the separable spatio-temporal +filter. diff --git a/docs/tutorials/plot_05_place_cells.md b/docs/tutorials/plot_05_place_cells.md new file mode 100644 index 00000000..ed81e904 --- /dev/null +++ b/docs/tutorials/plot_05_place_cells.md @@ -0,0 +1,489 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +```{code-cell} ipython3 +%matplotlib inline +``` + + +# Fit place cell + +The data for this example are from [Grosmark, Andres D., and György Buzsáki. "Diversity in neural firing dynamics supports both rigid and learned hippocampal sequences." Science 351.6280 (2016): 1440-1443](https://www.science.org/doi/full/10.1126/science.aad1935). + +```{code-cell} ipython3 +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import pynapple as nap +from scipy.ndimage import gaussian_filter + +import nemos as nmo + +# some helper plotting functions +from nemos import _documentation_utils as doc_plots + +# configure plots some +plt.style.use(nmo.styles.plot_style) +``` + +## Data Streaming + +Here we load the data from OSF. The data is a NWB file. + + +```{code-cell} ipython3 +path = nmo.fetch.fetch_data("Achilles_10252013.nwb") +``` + +## Pynapple +We are going to open the NWB file with pynapple + + +```{code-cell} ipython3 +data = nap.load_file(path) + +data +``` + +Let's extract the spike times, the position and the theta phase. + + +```{code-cell} ipython3 +spikes = data["units"] +position = data["position"] +theta = data["theta_phase"] +``` + +The NWB file also contains the time at which the animal was traversing the linear track. We can use it to restrict the position and assign it as the `time_support` of position. + + +```{code-cell} ipython3 +position = position.restrict(data["trials"]) +``` + +The recording contains both inhibitory and excitatory neurons. Here we will focus of the excitatory cells. Neurons have already been labelled before. + + +```{code-cell} ipython3 +spikes = spikes.getby_category("cell_type")["pE"] +``` + +We can discard the low firing neurons as well. + + +```{code-cell} ipython3 +spikes = spikes.getby_threshold("rate", 0.3) +``` + +## Place fields +Let's plot some data. We start by making place fields i.e firing rate as a function of position. + + +```{code-cell} ipython3 +pf = nap.compute_1d_tuning_curves(spikes, position, 50, position.time_support) +``` + +Let's do a quick sort of the place fields for display + + +```{code-cell} ipython3 +order = pf.idxmax().sort_values().index.values +``` + +Here each row is one neuron + + +```{code-cell} ipython3 +plt.figure(figsize=(12, 10)) +gs = plt.GridSpec(len(spikes), 1) +for i, n in enumerate(order): + plt.subplot(gs[i, 0]) + plt.fill_between(pf.index.values, np.zeros(len(pf)), pf[n].values) + if i < len(spikes) - 1: + plt.xticks([]) + else: + plt.xlabel("Position (cm)") + plt.yticks([]) +``` + +## Phase precession + +In addition to place modulation, place cells are also modulated by the theta oscillation. The phase at which neurons fire is dependant of the position. This phenomen is called "phase precession" (see [J. O’Keefe, M. L. Recce, "Phase relationship between hippocampal place units and the EEG theta rhythm." Hippocampus 3, 317–330 (1993).](https://doi.org/10.1002/hipo.450030307) + +Let's compute the response of the neuron as a function of both theta and position. The phase of theta has already been computed but we have to bring it to the same dimension as the position feature. While the position has been sampled at 40Hz, the theta phase has been computed at 1250Hz. +Later on during the analysis, we will use a bin size of 5 ms for counting the spikes. Since this corresponds to an intermediate frequency between 40 and 1250 Hz, we will bring all the features to 200Hz already. + + +```{code-cell} ipython3 +bin_size = 0.005 + +theta = theta.bin_average(bin_size, position.time_support) +theta = (theta + 2 * np.pi) % (2 * np.pi) + +data = nap.TsdFrame( + t=theta.t, + d=np.vstack( + (position.interpolate(theta, ep=position.time_support).values, theta.values) + ).T, + time_support=position.time_support, + columns=["position", "theta"], +) + +print(data) +``` + +`data` is a `TsdFrame` that contains the position and phase. Before calling `compute_2d_tuning_curves` from pynapple to observe the theta phase precession, we will restrict the analysis to the place field of one neuron. + +There are a lot of neurons but for this analysis, we will focus on one neuron only. + + +```{code-cell} ipython3 +neuron = 175 + +plt.figure(figsize=(5,3)) +plt.fill_between(pf[neuron].index.values, np.zeros(len(pf)), pf[neuron].values) +plt.xlabel("Position (cm)") +plt.ylabel("Firing rate (Hz)") +``` + +This neurons place field is between 0 and 60 cm within the linear track. Here we will use the `threshold` function of pynapple to quickly compute the epochs for which the animal is within the place field : + + +```{code-cell} ipython3 +within_ep = position.threshold(60.0, method="below").time_support +``` + +`within_ep` is an `IntervalSet`. We can now give it to `compute_2d_tuning_curves` along with the spiking activity and the position-phase features. + + +```{code-cell} ipython3 +tc_pos_theta, xybins = nap.compute_2d_tuning_curves(spikes, data, 20, within_ep) +``` + +To show the theta phase precession, we can also display the spike as a function of both position and theta. In this case, we use the function `value_from` from pynapple. + + +```{code-cell} ipython3 +theta_pos_spikes = spikes[neuron].value_from(data, ep = within_ep) +``` + +Now we can plot everything together : + + +```{code-cell} ipython3 +plt.figure() +gs = plt.GridSpec(2, 2) +plt.subplot(gs[0, 0]) +plt.fill_between(pf[neuron].index.values, np.zeros(len(pf)), pf[neuron].values) +plt.xlabel("Position (cm)") +plt.ylabel("Firing rate (Hz)") + +plt.subplot(gs[1, 0]) +extent = (xybins[0][0], xybins[0][-1], xybins[1][0], xybins[1][-1]) +plt.imshow(gaussian_filter(tc_pos_theta[neuron].T, 1), aspect="auto", origin="lower", extent=extent) +plt.xlabel("Position (cm)") +plt.ylabel("Theta Phase (rad)") + +plt.subplot(gs[1, 1]) +plt.plot(theta_pos_spikes["position"], theta_pos_spikes["theta"], "o", markersize=0.5) +plt.xlabel("Position (cm)") +plt.ylabel("Theta Phase (rad)") + +plt.tight_layout() +``` + +## Speed modulation +The speed at which the animal traverse the field is not homogeneous. Does it influence the firing rate of hippocampal neurons? We can compute tuning curves for speed as well as average speed across the maze. +In the next block, we compute the speed of the animal for each epoch (i.e. crossing of the linear track) by doing the difference of two consecutive position multiplied by the sampling rate of the position. + + +```{code-cell} ipython3 +speed = [] +for s, e in data.time_support.values: # Time support contains the epochs + pos_ep = data["position"].get(s, e) + speed_ep = np.abs(np.diff(pos_ep)) # Absolute difference of two consecutive points + speed_ep = np.pad(speed_ep, [0, 1], mode="edge") # Adding one point at the end to match the size of the position array + speed_ep = speed_ep * data.rate # Converting to cm/s + speed.append(speed_ep) + +speed = nap.Tsd(t=data.t, d=np.hstack(speed), time_support=data.time_support) +``` + +Now that we have the speed of the animal, we can compute the tuning curves for speed modulation. Here we call pynapple `compute_1d_tuning_curves`: + + +```{code-cell} ipython3 +tc_speed = nap.compute_1d_tuning_curves(spikes, speed, 20) +``` + +To assess the variabilty in speed when the animal is travering the linear track, we can compute the average speed and estimate the standard deviation. Here we use numpy only and put the results in a pandas `DataFrame`: + + +```{code-cell} ipython3 +bins = np.linspace(np.min(data["position"]), np.max(data["position"]), 20) + +idx = np.digitize(data["position"].values, bins) + +mean_speed = np.array([np.mean(speed[idx==i]) for i in np.unique(idx)]) +std_speed = np.array([np.std(speed[idx==i]) for i in np.unique(idx)]) +``` + +Here we plot the tuning curve of one neuron for speed as well as the average speed as a function of the animal position + + +```{code-cell} ipython3 +plt.figure(figsize=(8, 3)) +plt.subplot(121) +plt.plot(bins, mean_speed) +plt.fill_between( + bins, + mean_speed - std_speed, + mean_speed + std_speed, + alpha=0.1, +) +plt.xlabel("Position (cm)") +plt.ylabel("Speed (cm/s)") +plt.title("Animal speed") +plt.subplot(122) +plt.fill_between( + tc_speed.index.values, np.zeros(len(tc_speed)), tc_speed[neuron].values +) +plt.xlabel("Speed (cm/s)") +plt.ylabel("Firing rate (Hz)") +plt.title("Neuron {}".format(neuron)) +plt.tight_layout() +``` + +This neurons show a strong modulation of firing rate as a function of speed but we can also notice that the animal, on average, accelerates when travering the field. Is the speed tuning we observe a true modulation or spurious correlation caused by traversing the place field at different speed and for different theta phase? We can use NeMoS to model the activity and give the position, the phase and the speed as input variable. + +We will use speed, phase and position to model the activity of the neuron. +All the feature have already been brought to the same dimension thanks to `pynapple`. + + +```{code-cell} ipython3 +position = data["position"] +theta = data["theta"] +count = spikes[neuron].count(bin_size, data.time_support) + +print(position.shape) +print(theta.shape) +print(speed.shape) +print(count.shape) +``` + +## Basis evaluation + +For each feature, we will use a different set of basis : + + - position : `nmo.basis.MSplineBasis` + - theta phase : `nmo.basis.CyclicBSplineBasis` + - speed : `nmo.basis.MSplineBasis` + + +```{code-cell} ipython3 +position_basis = nmo.basis.MSplineBasis(n_basis_funcs=10) +phase_basis = nmo.basis.CyclicBSplineBasis(n_basis_funcs=12) +speed_basis = nmo.basis.MSplineBasis(n_basis_funcs=15) +``` + +In addition, we will consider position and phase to be a joint variable. In NeMoS, we can combine basis by multiplying them and adding them. In this case the final basis object for our model can be made in one line : + + +```{code-cell} ipython3 +basis = position_basis * phase_basis + speed_basis +``` + +The object basis only tell us how each basis covers the feature space. For each timestep, we need to _evaluate_ what are the features value. For that we can call NeMoS basis: + + +```{code-cell} ipython3 +X = basis(position, theta, speed) +``` + +`X` is our design matrix. For each timestamps, it contains the information about the current position, +speed and theta phase of the experiment. Notice how passing a pynapple object to the basis +also returns a `pynapple` object. + + +```{code-cell} ipython3 +print(X) +``` + +## Model learning + +We can now use the Poisson GLM from NeMoS to learn the model. + + +```{code-cell} ipython3 +glm = nmo.glm.GLM( + solver_kwargs=dict(tol=10**-12), + solver_name="LBFGS" +) + +glm.fit(X, count) +``` + +## Prediction + +Let's check first if our model can accurately predict the different tuning curves we displayed above. We can use the `predict` function of NeMoS and then compute new tuning curves + + +```{code-cell} ipython3 +predicted_rate = glm.predict(X) / bin_size + +glm_pf = nap.compute_1d_tuning_curves_continuous(predicted_rate[:, np.newaxis], position, 50) +glm_pos_theta, xybins = nap.compute_2d_tuning_curves_continuous( + predicted_rate[:, np.newaxis], data, 30, ep=within_ep +) +glm_speed = nap.compute_1d_tuning_curves_continuous(predicted_rate[:, np.newaxis], speed, 30) +``` + +Let's display both tuning curves together. + + +```{code-cell} ipython3 +fig = doc_plots.plot_position_phase_speed_tuning( + pf[neuron], + glm_pf[0], + tc_speed[neuron], + glm_speed[0], + tc_pos_theta[neuron], + glm_pos_theta[0], + xybins + ) +``` + +## Model selection + +While this model captures nicely the features-rate relationship, it is not necessarily the simplest model. Let's construct several models and evaluate their score to determine the best model. + +!!! note + To shorten this notebook, only a few combinations are tested. Feel free to expand this list. + + + +```{code-cell} ipython3 +models = { + "position": position_basis, + "position + speed": position_basis + speed_basis, + "position + phase": position_basis + phase_basis, + "position * phase + speed": position_basis * phase_basis + speed_basis, +} +features = { + "position": (position,), + "position + speed": (position, speed), + "position + phase": (position, theta), + "position * phase + speed": (position, theta, speed), +} +``` + +In a loop, we can (1) evaluate the basis, (2), fit the model, (3) compute the score and (4) predict the firing rate. For evaluating the score, we can define a train set of intervals and a test set of intervals. + + +```{code-cell} ipython3 +train_iset = position.time_support[::2] # Taking every other epoch +test_iset = position.time_support[1::2] +``` + +Let's train all the models. + + +```{code-cell} ipython3 +scores = {} +predicted_rates = {} + +for m in models: + print("1. Evaluating basis : ", m) + X = models[m](*features[m]) + + print("2. Fitting model : ", m) + glm.fit( + X.restrict(train_iset), + count.restrict(train_iset), + ) + + print("3. Scoring model : ", m) + scores[m] = glm.score( + X.restrict(test_iset), + count.restrict(test_iset), + score_type="pseudo-r2-McFadden", + ) + + print("4. Predicting rate") + predicted_rates[m] = glm.predict(X.restrict(test_iset)) / bin_size + + +scores = pd.Series(scores) +scores = scores.sort_values() +``` + +Let's compute scores for each models. + + +```{code-cell} ipython3 +plt.figure(figsize=(5, 3)) +plt.barh(np.arange(len(scores)), scores) +plt.yticks(np.arange(len(scores)), scores.index) +plt.xlabel("Pseudo r2") +plt.tight_layout() +``` + +Some models are doing better than others. + +!!! warning + A proper model comparison should be done by scoring models repetitively on various train and test set. Here we are only doing partial models comparison for the sake of conciseness. + +Alternatively, we can plot some tuning curves to compare each models visually. + + +```{code-cell} ipython3 +tuning_curves = {} + +for m in models: + tuning_curves[m] = { + "position": nap.compute_1d_tuning_curves_continuous( + predicted_rates[m][:, np.newaxis], position, 50, ep=test_iset + ), + "speed": nap.compute_1d_tuning_curves_continuous( + predicted_rates[m][:, np.newaxis], speed, 20, ep=test_iset + ), + } + +# recompute tuning from spikes restricting to the test-set +pf = nap.compute_1d_tuning_curves(spikes, position, 50, ep=test_iset) +tc_speed = nap.compute_1d_tuning_curves(spikes, speed, 20, ep=test_iset) + + +fig = plt.figure(figsize=(8, 4)) +outer_grid = fig.add_gridspec(2, 2) +for i, m in enumerate(models): + doc_plots.plot_position_speed_tuning( + outer_grid[i // 2, i % 2], + tuning_curves[m], + pf[neuron], + tc_speed[neuron], + m) + +plt.tight_layout() +plt.show() +``` + +## Conclusion + +Various combinations of features can lead to different results. Feel free to explore more. To go beyond this notebook, you can check the following references : + + - [Hardcastle, Kiah, et al. "A multiplexed, heterogeneous, and adaptive code for navigation in medial entorhinal cortex." Neuron 94.2 (2017): 375-387](https://www.cell.com/neuron/pdf/S0896-6273(17)30237-4.pdf) + + - [McClain, Kathryn, et al. "Position–theta-phase model of hippocampal place cell activity applied to quantification of running speed modulation of firing rate." Proceedings of the National Academy of Sciences 116.52 (2019): 27035-27042](https://www.pnas.org/doi/abs/10.1073/pnas.1912792116) + + - [Peyrache, Adrien, Natalie Schieferstein, and Gyorgy Buzsáki. "Transformation of the head-direction signal into a spatial code." Nature communications 8.1 (2017): 1752.](https://www.nature.com/articles/s41467-017-01908-3) diff --git a/docs/tutorials/plot_06_calcium_imaging.md b/docs/tutorials/plot_06_calcium_imaging.md new file mode 100644 index 00000000..06e78296 --- /dev/null +++ b/docs/tutorials/plot_06_calcium_imaging.md @@ -0,0 +1,339 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +```{code-cell} ipython3 +%matplotlib inline +``` + + +Fit Calcium Imaging +============ + + +For the example dataset, we will be working with a recording of a freely-moving mouse imaged with a Miniscope (1-photon imaging at 30Hz using the genetically encoded calcium indicator GCaMP6f). The area recorded for this experiment is the postsubiculum - a region that is known to contain head-direction cells, or cells that fire when the animal's head is pointing in a specific direction. + +The data were collected by Sofia Skromne Carrasco from the [Peyrache Lab](https://www.peyrachelab.com/). + +```{code-cell} ipython3 +import jax +import jax.numpy as jnp +import matplotlib.pyplot as plt +import pynapple as nap +from sklearn.linear_model import LinearRegression + +import nemos as nmo +``` + +configure plots + + +```{code-cell} ipython3 +plt.style.use(nmo.styles.plot_style) +``` + +## Data Streaming + +Here we load the data from OSF. The data is a NWB file. + + +```{code-cell} ipython3 +path = nmo.fetch.fetch_data("A0670-221213.nwb") +``` + +*** +## pynapple preprocessing + +Now that we have the file, let's load the data. The NWB file contains multiple entries. + + +```{code-cell} ipython3 +data = nap.load_file(path) +print(data) +``` + +In the NWB file, the calcium traces are saved the RoiResponseSeries field. Let's save them in a variable called 'transients' and print it. + + +```{code-cell} ipython3 +transients = data['RoiResponseSeries'] +print(transients) +``` + +`transients` is a `TsdFrame`. Each column contains the activity of one neuron. + +The mouse was recorded for a 20 minute recording epoch as we can see from the `time_support` property of the `transients` object. + + +```{code-cell} ipython3 +ep = transients.time_support +print(ep) +``` + +There are a few different ways we can explore the data. First, let's inspect the raw calcium traces for neurons 4 and 35 for the first 250 seconds of the experiment. + + +```{code-cell} ipython3 +fig, ax = plt.subplots(1, 2, figsize=(12, 4)) +ax[0].plot(transients[:, 4].get(0,250)) +ax[0].set_ylabel("Firing rate (Hz)") +ax[0].set_title("Trace 4") +ax[0].set_xlabel("Time(s)") +ax[1].plot(transients[:, 35].get(0,250)) +ax[1].set_title("Trace 35") +ax[1].set_xlabel("Time(s)") +plt.tight_layout() +``` + +You can see that the calcium signals are both nonnegative, and noisy. One (neuron 4) has much higher SNR than the other. We cannot typically resolve individual action potentials, but instead see slow calcium fluctuations that result from an unknown underlying electrical signal (estimating the spikes from calcium traces is known as _deconvolution_ and is beyond the scope of this demo). + + ++++ + +We can also plot tuning curves, plotting mean calcium activity as a function of head direction, using the function `compute_1d_tuning_curves_continuous`. +Here `data['ry']` is a `Tsd` that contains the angular head-direction of the animal between 0 and 2$\pi$. + + +```{code-cell} ipython3 +tcurves = nap.compute_1d_tuning_curves_continuous(transients, data['ry'], 120) +``` + +The function returns a pandas DataFrame. Let's plot the tuning curves for neurons 4 and 35. + + +```{code-cell} ipython3 +fig, ax = plt.subplots(1, 2, figsize=(12, 4)) +ax[0].plot(tcurves.iloc[:, 4]) +ax[0].set_xlabel("Angle (rad)") +ax[0].set_ylabel("Firing rate (Hz)") +ax[0].set_title("Trace 4") +ax[1].plot(tcurves.iloc[:, 35]) +ax[1].set_xlabel("Angle (rad)") +ax[1].set_title("Trace 35") +plt.tight_layout() +``` + +As a first processing step, let's bin the calcium traces to a 100ms resolution. + + +```{code-cell} ipython3 +Y = transients.bin_average(0.1, ep) +``` + +We can visualize the downsampled transients for the first 50 seconds of data. + + +```{code-cell} ipython3 +plt.figure() +plt.plot(transients[:,0].get(0, 50), linewidth=5, label="30 Hz") +plt.plot(Y[:,0].get(0, 50), '--', linewidth=2, label="10 Hz") +plt.xlabel("Time (s)") +plt.ylabel("Fluorescence") +plt.legend() +plt.show() +``` + +The downsampling did not destroy the fast transient dynamics, so seems fine to use. We can now move on to using NeMoS to fit a model. + + ++++ + +## Basis instantiation + +We can define a cyclic-BSpline for capturing the encoding of the heading angle, and a log-spaced raised cosine basis for the coupling filters between neurons. Note that we are not including a self-coupling (spike history) filter, because in practice we have found it results in overfitting. + +We can combine the two bases. + + +```{code-cell} ipython3 +heading_basis = nmo.basis.CyclicBSplineBasis(n_basis_funcs=12) +coupling_basis = nmo.basis.RaisedCosineBasisLog(3, mode="conv", window_size=10) +``` + +We need to make sure the design matrix will be full-rank by applying identifiability constraints to the Cyclic Bspline, and then combine the bases (the resturned object will be an `AdditiveBasis` object). + + +```{code-cell} ipython3 +heading_basis.identifiability_constraints = True +basis = heading_basis + coupling_basis +``` + +## Gamma GLM + +Until now, we have been modeling spike trains, and have used a Poisson distribution for the observation model. With calcium traces, things are quite different: we no longer have counts but continuous signals, so the Poisson assumption is no longer appropriate. A Gaussian model is also not ideal since the calcium traces are non-negative. To satisfy these constraints, we will use a Gamma distribution from NeMoS with a soft-plus non linearity. +!!! note "Non-linearity" + Different option are possible. With a soft-plus we are assuming an "additive" effect of the predictors, while an exponential non-linearity assumes multiplicative effects. Deciding which firing rate model works best is an empirical question. You can fit different configurations to see which one capture best the neural activity. + + +```{code-cell} ipython3 +model = nmo.glm.GLM( + solver_kwargs=dict(tol=10**-13), + regularizer="Ridge", + regularizer_strength=0.02, + observation_model=nmo.observation_models.GammaObservations(inverse_link_function=jax.nn.softplus) +) +``` + +We select one neuron to fit later, so remove it from the list of predictors + + +```{code-cell} ipython3 +neu = 4 +selected_neurons = jnp.hstack( + (jnp.arange(0, neu), jnp.arange(neu+1, Y.shape[1])) +) + +print(selected_neurons) +``` + +We need to bring the head-direction of the animal to the same size as the transients matrix. +We can use the function `bin_average` of pynapple. Notice how we pass the parameter `ep` +that is the `time_support` of the transients. + + +```{code-cell} ipython3 +head_direction = data['ry'].bin_average(0.1, ep) +``` + +Let's check that `head_direction` and `Y` are of the same size. + + +```{code-cell} ipython3 +print(head_direction.shape) +print(Y.shape) +``` + +## Design matrix + +We can now create the design matrix by combining the head-direction of the animal and the activity of all other neurons. + + + +```{code-cell} ipython3 +X = basis.compute_features(head_direction, Y[:, selected_neurons]) +``` + +## Train & test set + +Let's create a train epoch and a test epoch to fit and test the models. Since `X` is a pynapple time series, we can create `IntervalSet` objects to restrict them into a train set and test set. + + +```{code-cell} ipython3 +train_ep = nap.IntervalSet(start=X.time_support.start, end=X.time_support.get_intervals_center().t) +test_ep = X.time_support.set_diff(train_ep) # Removing the train_ep from time_support + +print(train_ep) +print(test_ep) +``` + +We can now restrict the `X` and `Y` to create our train set and test set. + + +```{code-cell} ipython3 +Xtrain = X.restrict(train_ep) +Ytrain = Y.restrict(train_ep) + +Xtest = X.restrict(test_ep) +Ytest = Y.restrict(test_ep) +``` + +## Model fitting + +It's time to fit the model on the data from the neuron we left out. + + +```{code-cell} ipython3 +model.fit(Xtrain, Ytrain[:, neu]) +``` + +## Model comparison + + ++++ + +We can compare this to scikit-learn [linear regression](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html). + + +```{code-cell} ipython3 +mdl = LinearRegression() +valid = ~jnp.isnan(Xtrain.d.sum(axis=1)) # Scikit learn does not like nans. +mdl.fit(Xtrain[valid], Ytrain[valid, neu]) +``` + +We now have 2 models we can compare. Let's predict the activity of the neuron during the test epoch. + + +```{code-cell} ipython3 +yp = model.predict(Xtest) +ylreg = mdl.predict(Xtest) # Notice that this is not a pynapple object. +``` + +Unfortunately scikit-learn has not adopted pynapple yet. Let's convert `ylreg` to a pynapple object to make our life easier. + + +```{code-cell} ipython3 +ylreg = nap.Tsd(t=yp.t, d=ylreg, time_support = yp.time_support) +``` + +Let's plot the predicted activity for the first 60 seconds of data. + + +```{code-cell} ipython3 +# mkdocs_gallery_thumbnail_number = 3 + +ep_to_plot = nap.IntervalSet(test_ep.start+20, test_ep.start+80) + +plt.figure() +plt.plot(Ytest[:,neu].restrict(ep_to_plot), "r", label="true", linewidth=2) +plt.plot(yp.restrict(ep_to_plot), "k", label="gamma-nemos", alpha=1) +plt.plot(ylreg.restrict(ep_to_plot), "g", label="linreg-sklearn", alpha=0.5) +plt.legend(loc='best') +plt.xlabel("Time (s)") +plt.ylabel("Fluorescence") +plt.show() +``` + +While there is some variability in the fit for both models, one advantage of the gamma distribution is clear: the nonnegativity constraint is followed with the data. + This is required for using GLMs to predict the firing rate, which must be positive, in response to simulated inputs. See Peyrache et al. 2018[$^{[1]}$](#ref-1) for an example of simulating activity with a GLM. + +Another way to compare models is to compute tuning curves. Here we use the function `compute_1d_tuning_curves_continuous` from pynapple. + + +```{code-cell} ipython3 +real_tcurves = nap.compute_1d_tuning_curves_continuous(transients, data['ry'], 120, ep=test_ep) +gamma_tcurves = nap.compute_1d_tuning_curves_continuous(yp, data['ry'], 120, ep=test_ep) +linreg_tcurves = nap.compute_1d_tuning_curves_continuous(ylreg, data['ry'], 120, ep=test_ep) +``` + +Let's plot them. + + +```{code-cell} ipython3 +plt.figure() +plt.plot(real_tcurves[neu], "r", label="true", linewidth=2) +plt.plot(gamma_tcurves, "k", label="gamma-nemos", alpha=1) +plt.plot(linreg_tcurves, "g", label="linreg-sklearn", alpha=0.5) +plt.legend(loc='best') +plt.ylabel("Fluorescence") +plt.xlabel("Head-direction (rad)") +plt.show() +``` + +!!! note "Gamma-GLM for Calcium Imaging Analysis" + Using Gamma-GLMs for fitting calcium imaging data is still in early stages, and hasn't been through + the levels of review and validation that they have for fitting spike data. Users should consider + this a relatively unexplored territory, and we hope that we hope that NeMoS will help researchers + explore this new space of models. + +## References + +[1] Peyrache, A., Schieferstein, N. & Buzsáki, G. Transformation of the head-direction signal into a spatial code. Nat Commun 8, 1752 (2017). https://doi.org/10.1038/s41467-017-01908-3 diff --git a/src/nemos/identifiability_constraints.py b/src/nemos/identifiability_constraints.py index 0ab515a9..4c97f170 100644 --- a/src/nemos/identifiability_constraints.py +++ b/src/nemos/identifiability_constraints.py @@ -256,7 +256,7 @@ def apply_identifiability_constraints_by_basis_component( feature_matrix: NDArray, add_intercept: bool = True, ) -> Tuple[NDArray, NDArray]: - """Apply identifiability constraint to a design matrix to each component of an additive basis. + """Apply identifiability constraint to a design matrix for each component of an additive basis. Parameters ---------- From bcc227611f271a9753f87128012a0b05ecd5d909 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 14 Nov 2024 16:57:30 -0500 Subject: [PATCH 020/107] fixed image tutorial 0 --- docs/background/README.md | 19 +- docs/background/_plot_04_modeling.py | 1 - docs/background/plot_00_conceptual_intro.md | 70 +- docs/background/plot_00_conceptual_intro.py | 208 ------ docs/background/plot_01_1D_basis_function.py | 167 ----- docs/background/plot_02_ND_basis_function.py | 301 -------- docs/background/plot_03_1D_convolution.py | 146 ---- docs/conf.py | 2 +- docs/how_to_guide/plot_02_glm_demo.py | 366 ---------- docs/how_to_guide/plot_03_glm_pytree.py | 298 -------- docs/how_to_guide/plot_04_population_glm.py | 185 ----- docs/how_to_guide/plot_05_batch_glm.py | 200 ----- .../plot_06_sklearn_pipeline_cv_demo.py | 506 ------------- docs/tutorials/plot_01_current_injection.py | 691 ------------------ docs/tutorials/plot_02_head_direction.py | 603 --------------- docs/tutorials/plot_03_grid_cells.py | 252 ------- docs/tutorials/plot_04_v1_cells.py | 293 -------- docs/tutorials/plot_05_place_cells.py | 412 ----------- docs/tutorials/plot_06_calcium_imaging.py | 319 -------- 19 files changed, 49 insertions(+), 4990 deletions(-) delete mode 100644 docs/background/_plot_04_modeling.py delete mode 100644 docs/background/plot_00_conceptual_intro.py delete mode 100644 docs/background/plot_01_1D_basis_function.py delete mode 100644 docs/background/plot_02_ND_basis_function.py delete mode 100644 docs/background/plot_03_1D_convolution.py delete mode 100644 docs/how_to_guide/plot_02_glm_demo.py delete mode 100644 docs/how_to_guide/plot_03_glm_pytree.py delete mode 100644 docs/how_to_guide/plot_04_population_glm.py delete mode 100644 docs/how_to_guide/plot_05_batch_glm.py delete mode 100644 docs/how_to_guide/plot_06_sklearn_pipeline_cv_demo.py delete mode 100644 docs/tutorials/plot_01_current_injection.py delete mode 100644 docs/tutorials/plot_02_head_direction.py delete mode 100644 docs/tutorials/plot_03_grid_cells.py delete mode 100644 docs/tutorials/plot_04_v1_cells.py delete mode 100644 docs/tutorials/plot_05_place_cells.py delete mode 100644 docs/tutorials/plot_06_calcium_imaging.py diff --git a/docs/background/README.md b/docs/background/README.md index 471ad027..743adf73 100644 --- a/docs/background/README.md +++ b/docs/background/README.md @@ -2,9 +2,16 @@ These notes aim to provide the essential background knowledge needed to understand the models and data processing techniques implemented in NeMoS. -??? attention "Additional requirements" - To run the tutorials, you may need to install some additional packages used for plotting and data fetching. - You can install all of the required packages with the following command: - ``` - pip install nemos[examples] - ``` +:::{admonition} Additional requirements +:class: attention +To run the tutorials, you may need to install some additional packages used for plotting and data fetching. +You can install all of the required packages with the following command: +``` +pip install nemos[examples] +``` + +::: + +## Index + +[Generalized Linear Models: An Introduction](#glm_intro_background) \ No newline at end of file diff --git a/docs/background/_plot_04_modeling.py b/docs/background/_plot_04_modeling.py deleted file mode 100644 index b18d386e..00000000 --- a/docs/background/_plot_04_modeling.py +++ /dev/null @@ -1 +0,0 @@ -"""GLM models.""" \ No newline at end of file diff --git a/docs/background/plot_00_conceptual_intro.md b/docs/background/plot_00_conceptual_intro.md index 7b9cf602..07894f19 100644 --- a/docs/background/plot_00_conceptual_intro.md +++ b/docs/background/plot_00_conceptual_intro.md @@ -14,7 +14,7 @@ kernelspec: ```{code-cell} ipython3 %matplotlib inline ``` - +(glm_intro_background)= # Generalized Linear Models: An Introduction Before we dive into using NeMoS, you might wonder: why model at all? Why not @@ -31,17 +31,16 @@ Before we dive into using NeMoS, you might wonder: why model at all? Why not only instantaneous current matters for firing rate) and makes specific quantitative predictions that can be used to compare among hypotheses. -!!! warning - - We are not claiming that the GLM will allow you to uniquely determine - causation! Like any statistical model or method, the GLM will not solve - causation for you (causation being a notoriously difficult problem in - science), but it will allow you to see the effect of adding and removing - different inputs on the predicted firing rate, which can facilitate - causal inferences. For more reading on causation and explanation in - neuroscience, the work of [Carl - Craver](https://philosophy.wustl.edu/people/carl-f-craver) is a good - place to start. +:::{attention} +We are not claiming that the GLM will allow you to uniquely determine +causation! Like any statistical model or method, the GLM will not solve +causation for you (causation being a notoriously difficult problem in +science), but it will allow you to see the effect of adding and removing +different inputs on the predicted firing rate, which can facilitate +causal inferences. For more reading on causation and explanation in +neuroscience, the work of [CarlCraver](https://philosophy.wustl.edu/people/carl-f-craver) +is a good place to start. +::: Now that we've convinced you that modeling is worthwhile, let's get started! How should we begin? @@ -71,7 +70,7 @@ model: a linear-nonlinear-Poisson model.
-Linear-Non Linear-Poisson illustration. +Linear-Non Linear-Poisson illustration.
LNP model schematic. Modified from Pillow et al., 2008.
@@ -88,16 +87,16 @@ rescales and shifts the input: $\bm{WX}+\bm{c}$. In the one-dimensional case, as in this example, this is equivalent to scaling it by a constant and adding an intercept. -!!! note +:::{note} +In geometry, this is more correctly referred to as an [affine +transformation](https://en.wikipedia.org/wiki/Affine_transformation), +which includes translations, scaling, and rotations. *Linear* +transformations are the subset of affine transformations that do not +include translations. - In geometry, this is more correctly referred to as an [affine - transformation](https://en.wikipedia.org/wiki/Affine_transformation), - which includes translations, scaling, and rotations. *Linear* - transformations are the subset of affine transformations that do not - include translations. - - In neuroscience, "linear" is the more common term, and we will use it - throughout. +In neuroscience, "linear" is the more common term, and we will use it +throughout. +::: This means that, in the 1d case, we have two knobs to transform the input: we can make it bigger or smaller, or we can shift it up or down. That is, we @@ -160,14 +159,14 @@ fig = doc_plots.lnp_schematic(input_feature, weights, intercepts, plot_nonlinear=True) ``` -!!! info - - In NeMoS, the non-linearity is kept fixed. We default to the exponential, - but a small number of other choices, such as soft-plus, are allowed. The - allowed choices guarantee both the non-negativity constraint described - above, as well as convexity, i.e. a single optimal solution. In - principle, one could choose a more complex non-linearity, but convexity - is not guaranteed in general. +:::{info} +In NeMoS, the non-linearity is kept fixed. We default to the exponential, +but a small number of other choices, such as soft-plus, are allowed. The +allowed choices guarantee both the non-negativity constraint described +above, as well as convexity, i.e. a single optimal solution. In +principle, one could choose a more complex non-linearity, but convexity +is not guaranteed in general. +::: Specifically, our firing rate is: $$ \lambda (t) = \exp (L(x(t)) = \exp (w x(t) + c) \tag{2}$$ @@ -210,13 +209,14 @@ $$ \sum\_t \log P(y(t) | \lambda(t)) \propto \sum\_t y(t) \log(\lambda(t)) - This is the objective function of the GLM model: we are trying to find the firing rate that maximizes the likelihood of the observed spike train. -!!! info +:::{info} - In NeMoS, the log-likelihood can be computed directly by calling the - `score` method, passing the predictors and the counts. The method first - computes the rate $\lambda(t)$ using (2) and then the likelihood using - (4). This method is used under the hood during optimization. +**In NeMoS, the log-likelihood can be computed directly by calling the +`score` method, passing the predictors and the counts. The method first +computes the rate $\lambda(t)$ using (2) and then the likelihood using +(4).** This method is used under the hood during optimization. +::: +++ diff --git a/docs/background/plot_00_conceptual_intro.py b/docs/background/plot_00_conceptual_intro.py deleted file mode 100644 index 30f7c5ff..00000000 --- a/docs/background/plot_00_conceptual_intro.py +++ /dev/null @@ -1,208 +0,0 @@ -# -*- coding: utf-8 -*- - -r"""# Generalized Linear Models: An Introduction - -Before we dive into using NeMoS, you might wonder: why model at all? Why not - just make a bunch of tuning curves and submit to *Science*? Modeling is - helpful because: - -- The tuning curve reflects the correlation between neuronal spiking and - feature of interest, but activity might be driven by some other highly - correlated input (after all, [correlation does not imply - causation](https://xkcd.com/552/)). How do you identify what's driving - activity? - -- Your model instantiates specific hypotheses about the system (e.g., that - only instantaneous current matters for firing rate) and makes specific - quantitative predictions that can be used to compare among hypotheses. - -!!! warning - - We are not claiming that the GLM will allow you to uniquely determine - causation! Like any statistical model or method, the GLM will not solve - causation for you (causation being a notoriously difficult problem in - science), but it will allow you to see the effect of adding and removing - different inputs on the predicted firing rate, which can facilitate - causal inferences. For more reading on causation and explanation in - neuroscience, the work of [Carl - Craver](https://philosophy.wustl.edu/people/carl-f-craver) is a good - place to start. - -Now that we've convinced you that modeling is worthwhile, let's get started! -How should we begin? - -When modeling, it's generally a good idea to start simple and add complexity -as needed. Simple models are: - -- Easier to understand, so you can more easily reason through why a model is - capturing or not capturing some feature of your data. - -- Easier to fit, so you can more quickly see how you did. - -- Surprisingly powerful, so you might not actually need all the bells and - whistles you expected. - -Therefore, let's start with the simplest possible model: the only input is the -instantaneous value of some input. This is equivalent to saying that the only -input influencing the firing rate of this neuron at time $t$ is the input it -received at that same time. As neuroscientists, we know this isn't true, but -given the data exploration we did above, it looks like a reasonable starting -place. We can always build in more complications later. - -### GLM components - -The Generalized Linear Model in neuroscience can also be thought of as a LNP -model: a linear-nonlinear-Poisson model. - -
- -Linear-Non Linear-Poisson illustration. -
LNP model schematic. Modified from Pillow et al., 2008.
-
- -The model receives some input and then: - -- sends it through a linear filter or transformation of some sort. -- passes that through a nonlinearity to get the *firing rate*. -- uses the firing rate as the mean of a Poisson process to generate *spikes*. - -Let's step through each of those in turn. - -Our input feature(s) are first passed through a linear transformation, which -rescales and shifts the input: $\bm{WX}+\bm{c}$. In the one-dimensional case, as -in this example, this is equivalent to scaling it by a constant and adding an -intercept. - -!!! note - - In geometry, this is more correctly referred to as an [affine - transformation](https://en.wikipedia.org/wiki/Affine_transformation), - which includes translations, scaling, and rotations. *Linear* - transformations are the subset of affine transformations that do not - include translations. - - In neuroscience, "linear" is the more common term, and we will use it - throughout. - -This means that, in the 1d case, we have two knobs to transform the input: we -can make it bigger or smaller, or we can shift it up or down. That is, we -compute: - -$$L(x(t)) = w x(t) + c \tag{1}$$ - -for some value of $w$ and $c$. Let's visualize some possible transformations -that our model can make with three cartoon neurons: - -""" - -import matplotlib.pyplot as plt - -# first import things -import numpy as np -import pynapple as nap - -import nemos as nmo - -# some helper plotting functions -from nemos import _documentation_utils as doc_plots - -# configure plots some -plt.style.use(nmo.styles.plot_style) - -# %% -# to simplify things, we will look at three simple LNP neuron models as -# described above, working through each step of the transform. First, we will -# plot the linear transformation of the input x: - -weights = np.asarray([.5, 4, -4]) -intercepts = np.asarray([.5, -3, -2]) - -# make a step function with some noise riding on top -input_feature = np.zeros(100) -input_feature[50:] = 1 -input_feature *= np.random.rand(100) -input_feature = nap.Tsd(np.linspace(0, 100, 100), input_feature) - -fig = doc_plots.lnp_schematic(input_feature, weights, intercepts) - -# %% -# -# With these linear transformations, we see that we can stretch or shrink the -# input and move its baseline up or down. Remember that the goal of this -# model is to predict the firing rate of the neuron. Thus, changing what -# happens when there's zero input is equivalent to changing the baseline firing -# rate of the neuron, so that's how we should think about the intercept. -# -# However, if this is meant to be the firing rate, there's something odd --- -# the output of the linear transformation is often negative, but firing rates -# have to be non-negative! That's what the nonlinearity handles: making sure our -# firing rate is always positive. We can visualize this second stage of the LNP model -# by adding the `plot_nonlinear` keyword to our `lnp_schematic()` plotting function: - -fig = doc_plots.lnp_schematic(input_feature, weights, intercepts, - plot_nonlinear=True) - -# %% -# !!! info -# -# In NeMoS, the non-linearity is kept fixed. We default to the exponential, -# but a small number of other choices, such as soft-plus, are allowed. The -# allowed choices guarantee both the non-negativity constraint described -# above, as well as convexity, i.e. a single optimal solution. In -# principle, one could choose a more complex non-linearity, but convexity -# is not guaranteed in general. -# -# Specifically, our firing rate is: -# $$ \lambda (t) = \exp (L(x(t)) = \exp (w x(t) + c) \tag{2}$$ -# -# We can see that the output of the nonlinear transformation is always -# positive, though note that the y-values have changed drastically. -# -# Now we're ready to look at the third step of the LNP model, and see what -# the generated spikes spikes look like! - -# mkdocs_gallery_thumbnail_number = 3 -fig = doc_plots.lnp_schematic(input_feature, weights, intercepts, - plot_nonlinear=True, plot_spikes=True) - -# %% -# -# Remember, spiking is a stochastic process. That means that a given firing -# rate can give rise to a variety of different spike trains; the plot above -# shows three possibilities for each neuron. Each spike train is a sample from -# a Poisson process with the mean equal to the firing rate, i.e., output of -# the linear-nonlinear parts of the model. -# -# Given that this is a stochastic process that could produce an infinite number -# of possible spike trains, how do we compare our model against the single -# observed spike train we have? We use the _log-likelihood_. This quantifies how -# likely it is to observe the given spike train for the computed firing rate: -# if $y(t)$ is the spike counts and $\lambda(t)$ the firing rate, the equation -# for the log-likelihood is -# -# $$ \sum\_t \log P(y(t) | \lambda(t)) = \sum\_t y(t) \log(\lambda(t)) - -# \lambda(t) - \log (y(t)!)\tag{3}$$ -# -# Note that this last $\log(y(t)!)$ term does not depend on $\lambda(t)$ and -# thus is independent of the model, so it is normally ignored. -# -# $$ \sum\_t \log P(y(t) | \lambda(t)) \propto \sum\_t y(t) \log(\lambda(t)) - -# \lambda(t))\tag{4}$$ -# -# This is the objective function of the GLM model: we are trying to find the -# firing rate that maximizes the likelihood of the observed spike train. -# -# !!! info -# -# In NeMoS, the log-likelihood can be computed directly by calling the -# `score` method, passing the predictors and the counts. The method first -# computes the rate $\lambda(t)$ using (2) and then the likelihood using -# (4). This method is used under the hood during optimization. - -# %% -# ## More general GLMs -# So far, we have focused on the relatively simple LNP model of spike generation, which is a special case of a GLM. The LNP model has some known shortcomings[$^{[1]}$](#ref-1). For instance, LNP ignores things like refactory periods and other history-dependent features of spiking in a neuron. As we will show in other demos, such _spike history filters_ can be built into GLMs to give more accurate results. We will also show how, if you have recordings from a large _population_ of neurons simultaneously, you can build connections between the neurons into the GLM in the form of _coupling filters_. This can help answer the degree to which activity is driven primarily by the input X, or by network influences in the population. -# -# ## References -# -# [1] Pillow, JW, Shlens, J, Paninski, L, Sher, A, Litke, AM, Chichilnisky, EJ, Simoncelli, EP (2008), "Spatio-temporal correlations and visual signalling in a complete neuronal population." Nature 454: 995-9. diff --git a/docs/background/plot_01_1D_basis_function.py b/docs/background/plot_01_1D_basis_function.py deleted file mode 100644 index 3e22f052..00000000 --- a/docs/background/plot_01_1D_basis_function.py +++ /dev/null @@ -1,167 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -# One-Dimensional Basis - -## Defining a 1D Basis Object - -We'll start by defining a 1D basis function object of the type `MSplineBasis`. -The hyperparameters required to initialize this class are: - -- The number of basis functions, which should be a positive integer. -- The order of the spline, which should be an integer greater than 1. -""" - -import matplotlib.pylab as plt -import numpy as np -import pynapple as nap - -import nemos as nmo - -# Initialize hyperparameters -order = 4 -n_basis = 10 - -# Define the 1D basis function object -bspline = nmo.basis.BSplineBasis(n_basis_funcs=n_basis, order=order) - -# %% -# ## Evaluating a Basis -# -# The `Basis` object is callable, and can be evaluated as a function. By default, the support of the basis -# is defined by the samples that we input to the `__call__` method, and covers from the smallest to the largest value. - -# Generate a time series of sample points -samples = nap.Tsd(t=np.arange(1001), d=np.linspace(0, 1,1001)) - -# Evaluate the basis at the sample points -eval_basis = bspline(samples) - -# Output information about the evaluated basis -print(f"Evaluated B-spline of order {order} with {eval_basis.shape[1]} " - f"basis element and {eval_basis.shape[0]} samples.") - -plt.figure() -plt.title("B-spline basis") -plt.plot(eval_basis) - -# %% -# ## Setting the basis support -# Sometimes, it is useful to restrict the basis to a fixed range. This can help manage outliers or ensure that -# your basis covers the same range across multiple experimental sessions. -# You can specify a range for the support of your basis by setting the `bounds` -# parameter at initialization. Evaluating the basis at any sample outside the bounds will result in a NaN. - -bspline_range = nmo.basis.BSplineBasis(n_basis_funcs=n_basis, order=order, bounds=(0.2, 0.8)) - -print("Evaluated basis:") -# 0.5 is within the support, 0.1 is outside the support -print(np.round(bspline_range([0.5, 0.1]), 3)) - - -# %% -# Let's compare the default behavior of basis (estimating the range from the samples) with -# the fixed range basis. - -fig, axs = plt.subplots(2,1, sharex=True) -plt.suptitle("B-spline basis ") -axs[0].plot(bspline(samples), color="k") -axs[0].set_title("default") -axs[1].plot(bspline_range(samples), color="tomato") -axs[1].set_title("bounds=[0.2, 0.8]") -plt.tight_layout() - -# %% -# ## Basis `mode` -# In constructing features, `Basis` objects can be used in two modalities: `"eval"` for evaluate or `"conv"` -# for convolve. These two modalities change the behavior of the `construct_features` method of `Basis`, in particular, -# -# - If a basis is in mode `"eval"`, then `construct_features` simply returns the evaluated basis. -# - If a basis is in mode `"conv"`, then `construct_features` will convolve the input with a kernel of basis -# with `window_size` specified by the user. -# -# Let's see how this two modalities operate. - -eval_mode = nmo.basis.MSplineBasis(n_basis_funcs=n_basis, mode="eval") -conv_mode = nmo.basis.MSplineBasis(n_basis_funcs=n_basis, mode="conv", window_size=100) - -# define an input -angles = np.linspace(0, np.pi*4, 201) -y = np.cos(angles) - -# compute features in the two modalities -eval_feature = eval_mode.compute_features(y) -conv_feature = conv_mode.compute_features(y) - -# plot results -fig, axs = plt.subplots( 3, 1, sharex="all", figsize=(6, 4)) - -# plot signal -axs[0].set_title("Input") -axs[0].plot(y) -axs[0].set_xticks([]) -axs[0].set_ylabel("signal", fontsize=12) - -# plot eval results -axs[1].set_title("eval features") -axs[1].imshow(eval_feature.T, aspect="auto") -axs[1].set_xticks([]) -axs[1].set_ylabel("basis", fontsize=12) - -# plot conv results -axs[2].set_title("convolutional features") -axs[2].imshow(conv_feature.T, aspect="auto") -axs[2].set_xlabel("time", fontsize=12) -axs[2].set_ylabel("basis", fontsize=12) -plt.tight_layout() - -# %% -# -# !!! note "NaN-Padding" -# Convolution is performed in "valid" mode, and then NaN-padded. The default behavior -# is padding left, which makes the output feature causal. -# This is why the first half of the `conv_feature` is full of NaNs and appears as white. -# If you want to learn more about convolutions, as well as how and when to change defaults -# check out the tutorial on [1D convolutions](../plot_03_1D_convolution). - -# %% -# Plotting the Basis Function Elements: -# -------------------------------------- -# We suggest visualizing the basis post-instantiation by evaluating each element on a set of equi-spaced sample points -# and then plotting the result. The method `Basis.evaluate_on_grid` is designed for this, as it generates and returns -# the equi-spaced samples along with the evaluated basis functions. The benefits of using Basis.evaluate_on_grid become -# particularly evident when working with multidimensional basis functions. You can find more details and visual -# background in the -# [2D basis elements plotting section](../plot_02_ND_basis_function/#plotting-2d-additive-basis-elements). - -# Call evaluate on grid on 100 sample points to generate samples and evaluate the basis at those samples -n_samples = 100 -equispaced_samples, eval_basis = bspline.evaluate_on_grid(n_samples) - -# Plot each basis element -plt.figure() -plt.title(f"B-spline basis with {eval_basis.shape[1]} elements\nevaluated at {eval_basis.shape[0]} sample points") -plt.plot(equispaced_samples, eval_basis) -plt.show() - -# %% -# Other Basis Types -# ----------------- -# Each basis type may necessitate specific hyperparameters for instantiation. For a comprehensive description, -# please refer to the [API Guide](../../../reference/nemos/basis). After instantiation, all classes -# share the same syntax for basis evaluation. The following is an example of how to instantiate and -# evaluate a log-spaced cosine raised function basis. - -# Instantiate the basis noting that the `RaisedCosineBasisLog` does not require an `order` parameter -raised_cosine_log = nmo.basis.RaisedCosineBasisLog(n_basis_funcs=10, width=1.5, time_scaling=50) - -# Evaluate the raised cosine basis at the equi-spaced sample points -# (same method in all Basis elements) -samples, eval_basis = raised_cosine_log.evaluate_on_grid(100) - -# Plot the evaluated log-spaced raised cosine basis -plt.figure() -plt.title(f"Log-spaced Raised Cosine basis with {eval_basis.shape[1]} elements") -plt.plot(samples, eval_basis) -plt.show() - diff --git a/docs/background/plot_02_ND_basis_function.py b/docs/background/plot_02_ND_basis_function.py deleted file mode 100644 index 095633e9..00000000 --- a/docs/background/plot_02_ND_basis_function.py +++ /dev/null @@ -1,301 +0,0 @@ -# -*- coding: utf-8 -*- - -r""" -# Multidimensional Basis - -## Background - -In many cases, it's necessary to model the response of a neuron to multiple different inputs -(such as velocity, spatial position, LFP phase, etc.). Such response functions can often be expressed as a linear -combination of some multidimensional basis elements. - -In this document, we introduce two strategies for defining a high-dimensional basis function by combining -two lower-dimensional bases. We refer to these strategies as "addition" and "multiplication" of bases, -and the resulting basis objects will be referred to as additive or multiplicative basis respectively. - - -Consider we have two inputs $\mathbf{x} \in \mathbb{R}^N,\; \mathbf{y}\in \mathbb{R}^M$. -Let's say we've defined two basis functions for these inputs: - -- $ [ a_0 (\mathbf{x}), ..., a_{k-1} (\mathbf{x}) ] $ for $\mathbf{x}$ -- $[b_0 (\mathbf{y}), ..., b_{h-1} (\mathbf{y}) ]$ for $\mathbf{y}$. - -These basis functions can be combined in the following ways: - -1. **Addition:** If we assume that there is no interaction between the stimuli, the response function can be adequately described by the sum of the individual components. The function is defined as: - $$ - f(\mathbf{x}, \mathbf{y}) \\approx \sum_{i=0}^{k-1} \\alpha_{i} \, a_i (\mathbf{x}) + \sum_{j=0}^{h-1} \\beta_j b_j(\mathbf{y}). - $$ - The resulting additive basis simply consists of the concatenation of the two basis sets: $$[A_0 (\mathbf{x}, \mathbf{y}), ..., A_{k+h-1} (\mathbf{x}, \mathbf{y})],$$ where - $$ - A_j(\mathbf{x}, \mathbf{y}) = \\begin{cases} a_j(\mathbf{x}) & \\text{if }\; j \leq k-1 \\\\\ b_{j-k+1}(\mathbf{y}) & \\text{otherwise.} \end{cases} - $$ - Note that we have a total of $k+h$ basis elements, and that each element is constant in one of the axis. - -2. **Multiplication:** If we expect the response function to capture arbitrary interactions between the inputs, we can approximate it as the external product of the two bases: - $$ - f(\mathbf{x}, \mathbf{y}) \\approx \sum_{i=0}^{k-1}\sum_{j=0}^{h-1} \\alpha_{ij} \, a_i (\mathbf{x}) b_j(\mathbf{y}). - $$ - In this case, the resulting basis consists of the $h \cdot k$ products of the individual bases: $$[A_0(\mathbf{x}, \mathbf{y}),..., A_{k \cdot h-1}(\mathbf{x}, \mathbf{y})],$$ - where, - $$ - A_{i \cdot h + j}(\mathbf{x}, \mathbf{y}) = a_i(\mathbf{x})b_{j}(\mathbf{y}), \; \\text{for} \; i=0,\dots, k-1 \; \\text{ and } \; j=0,\dots,h-1. - $$ - -In the subsequent sections, we will: - -1. Demonstrate the definition, evaluation, and visualization of 2D additive and multiplicative bases. -2. Illustrate how to iteratively apply addition and multiplication operations to extend to dimensions beyond two. - -## 2D Basis Functions - -Consider an instance where we want to capture a neuron's response to an animal's position within a given arena. -In this scenario, the stimuli are the 2D coordinates (x, y) that represent the animal's position at each time point. - -""" - -# %% -# ### Additive Basis Object -# One way to model the response to our 2D stimuli is to hypothesize that it decomposes into two factors: -# one due to the x-coordinate and another due to the y-coordinate. We can express this relationship as: -# $$ -# f(x,y) \\approx \sum_i \alpha_i \cdot a_i(x) + \sum_j \beta_j \cdot b_j(y). -# $$ -# Here, we simply add two basis objects, `a_basis` and `b_basis`, together to define the additive basis. - -import matplotlib.pyplot as plt -import numpy as np - -import nemos as nmo - -# Define 1D basis objects -a_basis = nmo.basis.MSplineBasis(n_basis_funcs=15, order=3) -b_basis = nmo.basis.RaisedCosineBasisLog(n_basis_funcs=14) - -# Define the 2D additive basis object -additive_basis = a_basis + b_basis - -# %% -# Evaluating the additive basis will require two inputs, one for each coordinate. -# The total number of elements of the additive basis will be the sum of the elements of the 1D basis. - -# Define a trajectory with 1000 time-points representing the recorded trajectory of the animal -T = 1000 - -# Define two variables -x_coord = np.linspace(0, 1, 1000) -y_coord = np.linspace(0, 1, 1000) - -# Evaluate the basis functions for the given trajectory. -eval_basis = additive_basis(x_coord, y_coord) - -print(f"Sum of two 1D splines with {eval_basis.shape[1]} " - f"basis element and {eval_basis.shape[0]} samples:\n" - f"\t- a_basis had {a_basis.n_basis_funcs} elements\n\t- b_basis had {b_basis.n_basis_funcs} elements.") - -# %% -# #### Plotting 2D Additive Basis Elements -# Let's select and plot a basis element from each of the basis we added. - -basis_a_element = 5 -basis_b_element = 1 -# Plot the 1D basis elements -fig, axs = plt.subplots(1, 2, figsize=(6, 3)) - -axs[0].set_title(f"$a_{{{basis_a_element}}}(x)$", color="b") -axs[0].plot(x_coord, a_basis(x_coord), "grey", alpha=.3) -axs[0].plot(x_coord, a_basis(x_coord)[:, basis_a_element], "b") -axs[0].set_xlabel("x-coord") - -axs[1].set_title(f"$b_{{{basis_b_element}}}(x)$", color="b") -axs[1].plot(y_coord, b_basis(x_coord), "grey", alpha=.3) -axs[1].plot(y_coord, b_basis(x_coord)[:, basis_b_element], "b") -axs[1].set_xlabel("y-coord") -plt.tight_layout() - -# %% -# We can visualize how these elements are extended in 2D by evaluating the additive basis -# on a grid of points that spans its domain and plotting the result. -# We use the `evaluate_on_grid` method for this. - -X, Y, Z = additive_basis.evaluate_on_grid(200, 200) - -# %% -# We can select the indices of the 2D additive basis that corresponds to the 1D original elements. - -basis_elem_idx = [basis_a_element, a_basis.n_basis_funcs + basis_b_element] - -# %% -# Finally, we can plot the 2D counterparts. -_, axs = plt.subplots(1, 2, subplot_kw={'aspect': 1}) - -# Plot the corresponding 2D elements. -# As expected, each element will be constant on one of the axis. -axs[0].set_title(f"$A_{{{basis_elem_idx[0]}}}(x,y) = " - f"a_{{{basis_a_element}}}(x)$", color="b") - -axs[1].set_title(f"$A_{{{basis_elem_idx[1]}}}(x,y) = " - f"b_{{{basis_b_element}}}(x)$", color="b") - -for cc in range(len(basis_elem_idx)): - axs[cc].contourf(X, Y, Z[..., basis_elem_idx[cc]], cmap="Blues") - axs[cc].set_xlabel("x-coord") - axs[cc].set_ylabel("y-coord") -plt.tight_layout() -plt.show() - -# %% -# ### Multiplicative Basis Object -# -# If the aim is to capture interactions between the coordinates, the response function can be modeled as the external -# product of two 1D basis functions. The approximation of the response function in this scenario would be: -# -# $$ -# f(x, y) \\approx \sum_{ij} \\alpha_{ij} \, a_i (x) b_j(y). -# $$ -# -# In this model, we define the 2D basis function as the product of two 1D basis objects. -# This allows the response to capture non-linear and interaction effects between the x and y coordinates. - -# 2D basis function as the product of the two 1D basis objects -prod_basis = a_basis * b_basis - -# %% -# Again evaluating the basis will require 2 inputs. -# The number of elements of the product basis will be the product of the elements of the two 1D bases. - -# Evaluate the product basis at the x and y coordinates -eval_basis = prod_basis(x_coord, y_coord) - -# Output the number of elements and samples of the evaluated basis, -# as well as the number of elements in the original 1D basis objects -print(f"Product of two 1D splines with {eval_basis.shape[1]} " - f"basis element and {eval_basis.shape[0]} samples:\n" - f"\t- a_basis had {a_basis.n_basis_funcs} elements\n\t- b_basis had {b_basis.n_basis_funcs} elements.") - -# %% -# #### Plotting 2D Multiplicative Basis Elements -# Plotting works in the same way as before. To demonstrate that, we select a few pairs of 1D basis elements, -# and we visualize the corresponding product. - -# Set this figure as the thumbnail -# mkdocs_gallery_thumbnail_number = 3 - -X, Y, Z = prod_basis.evaluate_on_grid(200, 200) - -# basis element pairs -element_pairs = [[0, 0], [5, 1], [10, 5]] - -# plot the 1D basis element and their product -fig, axs = plt.subplots(3,3,figsize=(8, 6)) -cc = 0 -for i, j in element_pairs: - # plot the element form a_basis - axs[cc, 0].plot(x_coord, a_basis(x_coord), "grey", alpha=.3) - axs[cc, 0].plot(x_coord, a_basis(x_coord)[:, i], "b") - axs[cc, 0].set_title(f"$a_{{{i}}}(x)$",color='b') - - # plot the element form b_basis - axs[cc, 1].plot(y_coord, b_basis(y_coord), "grey", alpha=.3) - axs[cc, 1].plot(y_coord, b_basis(y_coord)[:, j], "b") - axs[cc, 1].set_title(f"$b_{{{j}}}(y)$",color='b') - - # select & plot the corresponding product basis element - k = i * b_basis.n_basis_funcs + j - axs[cc, 2].contourf(X, Y, Z[:, :, k], cmap='Blues') - axs[cc, 2].set_title(f"$A_{{{k}}}(x,y) = a_{{{i}}}(x) \cdot b_{{{j}}}(y)$", color='b') - axs[cc, 2].set_xlabel('x-coord') - axs[cc, 2].set_ylabel('y-coord') - axs[cc, 2].set_aspect("equal") - - cc += 1 -axs[2, 0].set_xlabel('x-coord') -axs[2, 1].set_xlabel('y-coord') - -plt.tight_layout() - -# %% -# !!! info -# Basis objects of different types can be combined through multiplication or addition. -# This feature is particularly useful when one of the axes represents a periodic variable and another is non-periodic. -# A practical example would be characterizing the responses to position -# in a linear maze and the LFP phase angle. - - -# %% -# N-Dimensional Basis -# ------------------- -# Sometimes it may be useful to model even higher dimensional interactions, for example between the heding direction of -# an animal and its spatial position. In order to model an N-dimensional response function, you can combine -# N 1D basis objects using additions and multiplications. -# -# !!! warning -# If you multiply basis together, the dimension of the evaluated basis function -# will increase exponentially with the number of dimensions potentially causing memory errors. -# For example, evaluating a product of $N$ 1D bases with $T$ samples and $K$ basis element, -# will output a $K^N \times T$ matrix. - - -T = 10 -n_basis = 8 - -a_basis = nmo.basis.RaisedCosineBasisLinear(n_basis_funcs=n_basis) -b_basis = nmo.basis.RaisedCosineBasisLinear(n_basis_funcs=n_basis) -c_basis = nmo.basis.RaisedCosineBasisLinear(n_basis_funcs=n_basis) - -prod_basis_3 = a_basis * b_basis * c_basis -samples = np.linspace(0, 1, T) -eval_basis = prod_basis_3(samples, samples, samples) - -print(f"Product of three 1D splines results in {prod_basis_3.n_basis_funcs} " - f"basis elements.\nEvaluation output of shape {eval_basis.shape}") - -# %% -# The evaluation of the product of 3 basis is a 4 dimensional tensor; we can visualize slices of it. - - -X, Y, W, Z = prod_basis_3.evaluate_on_grid(30, 30, 30) - -# select any slice -slices = [17, 18, 19] -basis_elem_idx = 300 -vmax = Z[:, :, slices, basis_elem_idx].max() -fig, axs = plt.subplots(1, 3, figsize=(8, 3)) -cnt = 0 -for slice_i in slices: - X_slice = X[:, :, slice_i] - Y_slice = Y[:, :, slice_i] - - Z_slice = Z[:, :, slice_i] - axs[cnt].contourf(X_slice, Y_slice, Z_slice[:, :, basis_elem_idx], - cmap='Blues', vmin=0, vmax=vmax) - axs[cnt].set_title(f"Slice {slice_i}") - cnt += 1 - -plt.suptitle(f"Basis element: {basis_elem_idx}") -plt.tight_layout() -plt.show() - -# Check sparsity -print(f"Sparsity check: {(Z == 0).sum() / Z.size * 100: .2f}% of the evaluated basis is null.") - -# %% -# !!! info -# The evaluated basis is going to be **sparse** if the basis elements support do not cover the -# full domain of the basis. - -# %% -# Here we demonstrate a shortcut syntax for multiplying bases of the same class. -# This is achieved using the power operator with an integer exponent. - -# First, let's define a basis `power_basis` that is equivalent to `prod_basis_3`, -# but we use the power syntax this time: -power_basis = a_basis**3 - -# Now, evaluate the `prod_basis_3` on a 30x30x30 grid and get the last item, let's call it `Z_pow`: -Z_pow_syntax = power_basis.evaluate_on_grid(30, 30, 30)[-1] -Z_prod_syntax = (a_basis * a_basis * a_basis).evaluate_on_grid(30, 30, 30)[-1] - -# We can now assert that the original basis and the new `power_basis` match. -# If they do, the total number of mismatched entries should be zero. -print(f"Total mismatched entries: {(Z_pow_syntax != Z_prod_syntax).sum()}") diff --git a/docs/background/plot_03_1D_convolution.py b/docs/background/plot_03_1D_convolution.py deleted file mode 100644 index 79f6ddd9..00000000 --- a/docs/background/plot_03_1D_convolution.py +++ /dev/null @@ -1,146 +0,0 @@ -""" -One-dimensional convolutions -""" - -# %% -# ## Generate synthetic data -# Generate some simulated spike counts. - -import matplotlib.patches as patches -import matplotlib.pylab as plt -import numpy as np - -import nemos as nmo - -np.random.seed(10) -ws = 10 -# samples -n_samples = 100 - -spk = np.random.poisson(lam=0.1, size=(n_samples, )) - -# add borders (extreme case, general border effect are represented) -spk[0] = 1 -spk[3] = 1 -spk[-1] = 1 -spk[-4] = 1 - - -# %% -# ## Convolution in `"valid"` mode -# Generate and plot a filter, then execute a convolution in "valid" mode for all trials and neurons. -# -# !!! info -# The `"valid"` mode of convolution only calculates the product when the two input vectors overlap completely, -# avoiding border artifacts. The outcome of such a convolution will -# be an array of `max(M,N) - min(M,N) + 1` elements in length, where `M` and `N` represent the number -# of elements in the arrays being convolved. For more detailed information on this, -# see [jax.numpy.convolve](https://jax.readthedocs.io/en/latest/_autosummary/jax.numpy.convolve.html). - - -# create three filters -basis_obj = nmo.basis.RaisedCosineBasisLinear(n_basis_funcs=3) -_, w = basis_obj.evaluate_on_grid(ws) - -plt.plot(w) - -spk_conv = nmo.convolve.reshape_convolve(spk, w) - -# valid convolution should be of shape n_samples - ws + 1 -print(f"Shape of the convolution output: {spk_conv.shape}") - -# %% -# ## Causal, Anti-Causal, and Acausal filters -# NaN padding appropriately the output of the convolution allows to model causal, anti-causal and acausal filters. -# A causal filter captures how an event or task variable influences the future firing-rate. -# An example usage case would be that of characterizing the refractory period of a neuron -# (i.e. the drop in firing rate immediately after a spike event). Another example could be characterizing how -# the current position of an animal in a maze would affect its future spiking activity. -# -# On the other hand, if we are interested in capturing the firing rate modulation before an event occurs we may want -# to use an anti-causal filter. An example of that may be the preparatory activity of pre-motor cortex that happens -# before a movement is initiated (here the event is. "movement onset"). -# -# Finally, if one wants to capture both causal -# and anti-causal effects one should use the acausal filters. -# Below we provide a function that runs the convolution in "valid" mode and pads the convolution output -# for the different filter types. - - -# pad according to the causal direction of the filter, after squeeze, -# the dimension is (n_filters, n_samples) -spk_causal_conv = nmo.convolve.create_convolutional_predictor( - w, spk, predictor_causality="causal" -) -spk_anticausal_conv = nmo.convolve.create_convolutional_predictor( - w, spk, predictor_causality="anti-causal" -) -spk_acausal_conv = nmo.convolve.create_convolutional_predictor( - w, spk, predictor_causality="acausal" -) - - -# %% -# Plot the results - -# NaN padded area -rect_causal = patches.Rectangle((0, -2.5), ws, 5, alpha=0.3, color='grey') -rect_anticausal = patches.Rectangle((len(spk)-ws, -2.5), ws, 5, alpha=0.3, color='grey') -rect_acausal_left = patches.Rectangle((0, -2.5), (ws-1)//2, 5, alpha=0.3, color='grey') -rect_acausal_right = patches.Rectangle((len(spk) - (ws-1)//2, -2.5), (ws-1)//2, 5, alpha=0.3, color='grey') - -# Set this figure as the thumbnail -# mkdocs_gallery_thumbnail_number = 2 - -plt.figure(figsize=(6, 4)) - -shift_spk = - spk - 0.1 -ax = plt.subplot(311) - -plt.title('valid + nan-pad') -ax.add_patch(rect_causal) -plt.vlines(np.arange(spk.shape[0]), 0, shift_spk, color='k') -plt.plot(np.arange(spk.shape[0]), spk_causal_conv) -plt.ylabel('causal') - -ax = plt.subplot(312) -ax.add_patch(rect_anticausal) -plt.vlines(np.arange(spk.shape[0]), 0, shift_spk, color='k') -plt.plot(np.arange(spk.shape[0]), spk_anticausal_conv) -plt.ylabel('anti-causal') - -ax = plt.subplot(313) -ax.add_patch(rect_acausal_left) -ax.add_patch(rect_acausal_right) -plt.vlines(np.arange(spk.shape[0]), 0, shift_spk, color='k') -plt.plot(np.arange(spk.shape[0]), spk_acausal_conv) -plt.ylabel('acausal') -plt.tight_layout() - -# %% -# ## Convolve using `Basis.compute_features` -# All the parameters of `create_convolutional_predictor` can be passed to a `Basis` directly -# at initialization. Note that you must set `mode == "conv"` to actually perform convolution -# with `Basis.compute_features`. Let's see how we can get the same results through `Basis`. - -# define basis with different predictor causality -causal_basis = nmo.basis.RaisedCosineBasisLinear( - n_basis_funcs=3, mode="conv", window_size=ws, - predictor_causality="causal" -) - -acausal_basis = nmo.basis.RaisedCosineBasisLinear( - n_basis_funcs=3, mode="conv", window_size=ws, - predictor_causality="acausal" -) - -anticausal_basis = nmo.basis.RaisedCosineBasisLinear( - n_basis_funcs=3, mode="conv", window_size=ws, - predictor_causality="anti-causal" -) - -# compute convolutions -basis_causal_conv = causal_basis.compute_features(spk) -basis_acausal_conv = acausal_basis.compute_features(spk) -basis_anticausal_conv = anticausal_basis.compute_features(spk) - diff --git a/docs/conf.py b/docs/conf.py index 9a0aa79e..b7f4b9a0 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -158,7 +158,7 @@ # Path for static files (custom stylesheets or JavaScript) -html_static_path = ['assets/stylesheets'] +html_static_path = ['assets/stylesheets', "assets"] html_css_files = ['custom.css'] html_js_files = [ diff --git a/docs/how_to_guide/plot_02_glm_demo.py b/docs/how_to_guide/plot_02_glm_demo.py deleted file mode 100644 index f1c6e3b2..00000000 --- a/docs/how_to_guide/plot_02_glm_demo.py +++ /dev/null @@ -1,366 +0,0 @@ -""" -# GLM Demo: Toy Model Examples - -!!! warning - This demonstration is currently in its alpha stage. It presents various regularization techniques on - GLMs trained on a Gaussian noise stimuli, and a minimal example of fitting and simulating a pair of coupled - neurons. More work needs to be done to properly compare the performance of the regularization strategies on - realistic simulations and real neural recordings. - -## Introduction - -In this demo we will work through two toy examples of a Poisson-GLM on synthetic data: a purely feed-forward input model -and a recurrently coupled model. - -In particular, we will learn how to: - -- Define & configurate a GLM object. -- Fit the model -- Cross-validate the model with `sklearn` -- Simulate spike trains. - -Before digging into the GLM module, let's first import the packages - we are going to use for this tutorial, and generate some synthetic - data. - -""" - -import jax -import matplotlib.pyplot as plt -import numpy as np -from matplotlib.patches import Rectangle -from sklearn import model_selection - -import nemos as nmo - -np.random.seed(111) -# random design tensor. Shape (n_time_points, n_features). -X = 0.5*np.random.normal(size=(100, 5)) - -# log-rates & weights, shape (1, ) and (n_features, ) respectively. -b_true = np.zeros((1, )) -w_true = np.random.normal(size=(5, )) - -# sparsify weights -w_true[1:4] = 0. - -# generate counts -rate = jax.numpy.exp(jax.numpy.einsum("k,tk->t", w_true, X) + b_true) -spikes = np.random.poisson(rate) - -# %% -# ## The Feed-Forward GLM -# -# ### Model Definition -# The class implementing the feed-forward GLM is `nemos.glm.GLM`. -# In order to define the class, one **must** provide: -# -# - **Observation Model**: The observation model for the GLM, e.g. an object of the class of type -# `nemos.observation_models.Observations`. So far, only the `PoissonObservations` -# model has been implemented. -# - **Regularizer**: The desired regularizer, e.g. an object of the `nemos.regularizer.Regularizer` class. -# Currently, we implemented the un-regularized, Ridge, Lasso, and Group-Lasso regularization. -# -# The default for the GLM class is the `PoissonObservations` with log-link function with a Ridge regularization. -# Here is how to define the model. - -# default Poisson GLM with Ridge regularization and Poisson observation model. -model = nmo.glm.GLM() - -print("Regularization type: ", type(model.regularizer)) -print("Observation model:", type(model.observation_model)) - -# %% -# ### Model Configuration -# One could visualize the model hyperparameters by calling `get_params` method. - -# get the glm model parameters only -print("\nGLM model parameters:") -for key, value in model.get_params(deep=False).items(): - print(f"\t- {key}: {value}") - -# get the glm model parameters, including the all the -# attributes -print("\nNested parameters:") -for key, value in model.get_params(deep=True).items(): - if key in model.get_params(deep=False): - continue - print(f"\t- {key}: {value}") - -# %% -# These parameters can be configured at initialization and/or -# set after the model is initialized with the following syntax: - -# Poisson observation model with soft-plus NL -observation_models = nmo.observation_models.PoissonObservations(jax.nn.softplus) - - -# define the GLM -model = nmo.glm.GLM( - observation_model=observation_models, - solver_name="LBFGS", - solver_kwargs={"tol":10**-10}, -) - -print("Regularizer type: ", type(model.regularizer)) -print("Observation model:", type(model.observation_model)) - -# %% -# Hyperparameters can be set at any moment via the `set_params` method. - -model.set_params( - regularizer=nmo.regularizer.Lasso(), - observation_model__inverse_link_function=jax.numpy.exp -) - -print("Updated regularizer: ", model.regularizer) -print("Updated NL: ", model.observation_model.inverse_link_function) - -# %% -# !!! warning -# Each `Regularizer` has an associated attribute `Regularizer.allowed_solvers` -# which lists the optimizers that are suited for each optimization problem. -# For example, a `Ridge` is differentiable and can be fit with `GradientDescent` -# , `BFGS`, etc., while a `Lasso` should use the `ProximalGradient` method instead. -# If the provided `solver_name` is not listed in the `allowed_solvers` this will raise an -# exception. - -# %% -# ### Model Fit -# Fitting the model is as straight forward as calling the `model.fit` -# providing the design tensor and the population counts. -# Additionally one may provide an initial parameter guess. -# The same exact syntax works for any configuration. - -# fit a ridge regression Poisson GLM -model = nmo.glm.GLM(regularizer="Ridge", regularizer_strength=0.1) -model.fit(X, spikes) - -print("Ridge results") -print("True weights: ", w_true) -print("Recovered weights: ", model.coef_) - -# %% -# ## K-fold Cross Validation with `sklearn` -# Our implementation follows the `scikit-learn` api, this enables us -# to take advantage of the `scikit-learn` tool-box seamlessly, while at the same time -# we take advantage of the `jax` GPU acceleration and auto-differentiation in the -# back-end. -# -# Here is an example of how we can perform 5-fold cross-validation via `scikit-learn`. -# -# **Ridge** - -parameter_grid = {"regularizer_strength": np.logspace(-1.5, 1.5, 6)} -# in practice, you should use more folds than 2, but for the purposes of this -# demo, 2 is sufficient. -cls = model_selection.GridSearchCV(model, parameter_grid, cv=2) -cls.fit(X, spikes) - -print("Ridge results ") -print("Best hyperparameter: ", cls.best_params_) -print("True weights: ", w_true) -print("Recovered weights: ", cls.best_estimator_.coef_) - -# %% -# We can compare the Ridge cross-validated results with other regularization schemes. -# -# **Lasso** - -model.set_params(regularizer=nmo.regularizer.Lasso(), solver_name="ProximalGradient") -cls = model_selection.GridSearchCV(model, parameter_grid, cv=2) -cls.fit(X, spikes) - -print("Lasso results ") -print("Best hyperparameter: ", cls.best_params_) -print("True weights: ", w_true) -print("Recovered weights: ", cls.best_estimator_.coef_) - -# %% -# **Group Lasso** - -# define groups by masking. Mask size (n_groups, n_features) -mask = np.zeros((2, 5)) -mask[0, [0, -1]] = 1 -mask[1, 1:-1] = 1 - -regularizer = nmo.regularizer.GroupLasso(mask=mask) -model.set_params(regularizer=regularizer, solver_name="ProximalGradient") -cls = model_selection.GridSearchCV(model, parameter_grid, cv=2) -cls.fit(X, spikes) - -print("\nGroup Lasso results") -print("Group mask: :") -print(mask) -print("Best hyperparameter: ", cls.best_params_) -print("True weights: ", w_true) -print("Recovered weights: ", cls.best_estimator_.coef_) - -# %% -# ## Simulate Spikes -# We can generate spikes in response to a feedforward-stimuli -# through the `model.simulate` method. - -# here we are creating a new data input, of 20 timepoints (arbitrary) -# with the same number of features (mandatory) -Xnew = np.random.normal(size=(20, ) + X.shape[1:]) -# generate a random key given a seed -random_key = jax.random.key(123) -spikes, rates = model.simulate(random_key, Xnew) - -plt.figure() -plt.eventplot(np.where(spikes)[0]) - - -# %% -# ## Simulate a Recurrently Coupled Network -# In this section, we will show you how to generate spikes from a population; We assume that the coupling -# filters are known or inferred. -# -# !!! warning -# Making sure that the dynamics of your recurrent neural network are stable is non-trivial[$^{[1]}$](#ref-1). In particular, -# coupling weights obtained by fitting a GLM by maximum-likelihood can generate unstable dynamics. If the -# dynamics of your recurrently coupled model are unstable, you can try a `soft-plus` non-linearity -# instead of an exponential, and you can "shrink" your weights until stability is reached. -# - -# Neural population parameters -n_neurons = 2 -coupling_filter_duration = 100 - -# %% -# Let's define the coupling filters that we will use to simulate -# the pairwise interactions between the neurons. We will model the -# filters as a difference of two Gamma probability density function. -# The negative component will capture inhibitory effects such as the -# refractory period of a neuron, while the positive component will -# describe excitation. - -np.random.seed(101) - -# Gamma parameter for the inhibitory component of the filter -inhib_a = 1 -inhib_b = 1 - -# Gamma parameters for the excitatory component of the filter -excit_a = np.random.uniform(1.1, 5, size=(n_neurons, n_neurons)) -excit_b = np.random.uniform(1.1, 5, size=(n_neurons, n_neurons)) - -# define 2x2 coupling filters of the specific with create_temporal_filter -coupling_filter_bank = np.zeros((coupling_filter_duration, n_neurons, n_neurons)) -for unit_i in range(n_neurons): - for unit_j in range(n_neurons): - coupling_filter_bank[:, unit_i, unit_j] = nmo.simulation.difference_of_gammas( - coupling_filter_duration, - inhib_a=inhib_a, - excit_a=excit_a[unit_i, unit_j], - inhib_b=inhib_b, - excit_b=excit_b[unit_i, unit_j], - ) - -# shrink the filters for simulation stability -coupling_filter_bank *= 0.8 - -# define a basis function -n_basis_funcs = 20 -basis = nmo.basis.RaisedCosineBasisLog(n_basis_funcs) - -# approximate the coupling filters in terms of the basis function -_, coupling_basis = basis.evaluate_on_grid(coupling_filter_bank.shape[0]) -coupling_coeff = nmo.simulation.regress_filter(coupling_filter_bank, coupling_basis) -intercept = -4 * np.ones(n_neurons) - -# %% -# We can check that our approximation worked by plotting the original filters -# and the basis expansion - -# plot coupling functions -n_basis_coupling = coupling_basis.shape[1] -fig, axs = plt.subplots(n_neurons, n_neurons) -plt.suptitle("Coupling filters") -for unit_i in range(n_neurons): - for unit_j in range(n_neurons): - axs[unit_i, unit_j].set_title(f"unit {unit_j} -> unit {unit_i}") - coeff = coupling_coeff[unit_i, unit_j] - axs[unit_i, unit_j].plot(coupling_filter_bank[:, unit_i, unit_j], label="gamma difference") - axs[unit_i, unit_j].plot(np.dot(coupling_basis, coeff), ls="--", color="k", label="basis function") -axs[0, 0].legend() -plt.tight_layout() - -# %% -# Define a squared stimulus current for the first neuron, and no stimulus for -# the second neuron - -# define a squared current parameters -simulation_duration = 1000 -stimulus_onset = 200 -stimulus_offset = 500 -stimulus_intensity = 1.5 - -# create the input tensor of shape (n_samples, n_neurons, n_dimension_stimuli) -feedforward_input = np.zeros((simulation_duration, n_neurons, 1)) - -# inject square input to the first neuron only -feedforward_input[stimulus_onset: stimulus_offset, 0] = stimulus_intensity - -# plot the input -fig, axs = plt.subplots(1,2) -plt.suptitle("Feedforward inputs") -axs[0].set_title("Input to neuron 0") -axs[0].plot(feedforward_input[:, 0]) - -axs[1].set_title("Input to neuron 1") -axs[1].plot(feedforward_input[:, 1]) -axs[1].set_ylim(axs[0].get_ylim()) - - -# the input for the simulation will be the dot product -# of input_coeff with the feedforward_input -input_coeff = np.ones((n_neurons, 1)) - - -# initialize the spikes for the recurrent simulation -init_spikes = np.zeros((coupling_filter_duration, n_neurons)) - - -# %% -# We can now simulate spikes by calling the `simulate_recurrent` function for the `nemos.simulate` module. - -# call simulate, with both the recurrent coupling -# and the input -spikes, rates = nmo.simulation.simulate_recurrent( - coupling_coef=coupling_coeff, - feedforward_coef=input_coeff, - intercepts=intercept, - random_key=jax.random.key(123), - feedforward_input=feedforward_input, - coupling_basis_matrix=coupling_basis, - init_y=init_spikes -) - -# %% -# And finally plot the results for both neurons. - -# mkdocs_gallery_thumbnail_number = 4 -plt.figure() -ax = plt.subplot(111) - -ax.spines['top'].set_visible(False) -ax.spines['right'].set_visible(False) - -patch = Rectangle((200, -0.011), 300, 0.15, alpha=0.2, color="grey") - -p0, = plt.plot(rates[:, 0]) -p1, = plt.plot(rates[:, 1]) - -plt.vlines(np.where(spikes[:, 0])[0], 0.00, 0.01, color=p0.get_color(), label="rate neuron 0") -plt.vlines(np.where(spikes[:, 1])[0], -0.01, 0.00, color=p1.get_color(), label="rate neuron 1") -plt.plot(jax.nn.softplus(input_coeff[0] * feedforward_input[:, 0, 0] + intercept[0]), color='k', lw=0.8, label="stimulus") -ax.add_patch(patch) -plt.ylim(-0.011, .13) -plt.ylabel("count/bin") -plt.legend() - -# %% -# ## References -# [1] Arribas, Diego, Yuan Zhao, and Il Memming Park. "Rescuing neural spike train models from bad MLE." Advances in Neural Information Processing Systems 33 (2020): 2293-2303. diff --git a/docs/how_to_guide/plot_03_glm_pytree.py b/docs/how_to_guide/plot_03_glm_pytree.py deleted file mode 100644 index 02181d32..00000000 --- a/docs/how_to_guide/plot_03_glm_pytree.py +++ /dev/null @@ -1,298 +0,0 @@ -"""# FeaturePytree example - -This small example notebook shows how to use our custom FeaturePytree objects -instead of arrays to represent the design matrix. It will show that these two -representations are equivalent. - -This demo will fit the Poisson-GLM to some synthetic data. We will first show -the simple case, with a single neuron receiving some input. We will then show a -two-neuron system, to demonstrate how FeaturePytree can make it easier to -separate examine separate types of inputs. - -First, however, let's briefly discuss FeaturePytrees. - -""" -import jax -import jax.numpy as jnp -import numpy as np - -import nemos as nmo - -np.random.seed(111) - -# %% -# ## FeaturePytrees -# -# A FeaturePytree is a custom NeMoS object used to represent design matrices, -# GLM coefficients, and other similar variables. It is a simple -# [pytree](https://jax.readthedocs.io/en/latest/pytrees.html), a dictionary -# with strings as keys and arrays as values. These arrays must all have the -# same number of elements along the first dimension, which represents the time -# points, but can have different numbers of elements along the other dimensions -# (and even different numbers of dimensions). - -example_pytree = nmo.pytrees.FeaturePytree(feature_0=np.random.normal(size=(100, 1, 2)), - feature_1=np.random.normal(size=(100, 2)), - feature_2=np.random.normal(size=(100, 5))) -example_pytree - -# %% -# -# FeaturePytrees can be indexed into like dictionary, so we can grab a -# single one of their features: - -example_pytree['feature_0'].shape - -# %% -# -# We can grab the number of time points by getting the length or using the -# `shape` attribute - -print(len(example_pytree)) -print(example_pytree.shape) - -# %% -# -# We can also jointly index into the FeaturePytree's leaves: - -example_pytree[:10] - -# %% -# -# We can add new features after initialization, as long as they have the same -# number of time points. - -example_pytree['feature_3'] = np.zeros((100, 2, 4)) - -# %% -# -# However, if we try to add a new feature with the wrong number of time points, -# we'll get an exception: - -try: - example_pytree['feature_4'] = np.zeros((99, 2, 4)) -except ValueError as e: - print(e) - -# %% -# -# Similarly, if we try to add a feature that's not an array: - -try: - example_pytree['feature_4'] = "Strings are very predictive" -except ValueError as e: - print(e) - -# %% -# -# FeaturePytrees are intended to be used with -# [jax.tree_util.tree_map](https://jax.readthedocs.io/en/latest/_autosummary/jax.tree_util.tree_map.html), -# a useful function for performing computations on arbitrary pytrees, -# preserving their structure. - -# %% -# We can map lambda functions: -mapped = jax.tree_util.tree_map(lambda x: x**2, example_pytree) -print(mapped) -mapped['feature_1'] -# %% -# Or functions from jax or numpy that operate on arrays: -mapped = jax.tree_util.tree_map(jnp.exp, example_pytree) -print(mapped) -mapped['feature_1'] -# %% -# We can change the dimensionality of our pytree: -mapped = jax.tree_util.tree_map(lambda x: jnp.mean(x, axis=-1), example_pytree) -print(mapped) -mapped['feature_1'] -# %% -# Or the number of time points: -mapped = jax.tree_util.tree_map(lambda x: x[::10], example_pytree) -print(mapped) -mapped['feature_1'] -# %% -# -# If we map something whose output cannot be a FeaturePytree (because its -# values are scalars or non-arrays), we return a dictionary of arrays instead: -print(jax.tree_util.tree_map(jnp.mean, example_pytree)) -print(jax.tree_util.tree_map(lambda x: x.shape, example_pytree)) -import matplotlib.pyplot as plt -import pynapple as nap - -# %% -# -# ## FeaturePytrees and GLM -# -# These properties make FeaturePytrees useful for representing design matrices -# and similar objects for the GLM. -# -# First, let's get our dataset and do some initial exploration of it. To do so, -# we'll use pynapple to [stream -# data](https://pynapple.org/examples/tutorial_pynapple_dandi.html) -# from the DANDI archive. -# -# !!! attention -# -# We need some additional packages for this portion, which you can install -# with `pip install dandi pynapple` - -io = nmo.fetch.download_dandi_data( - "000582", - "sub-11265/sub-11265_ses-07020602_behavior+ecephys.nwb", -) - -nwb = nap.NWBFile(io.read(), lazy_loading=False) - -print(nwb) - -# %% -# -# This data set has cells that are tuned for head direction and 2d position. -# Let's compute some simple tuning curves to see if we can find a cell that -# looks tuned for both. - -tc, binsxy = nap.compute_2d_tuning_curves(nwb['units'], nwb['SpatialSeriesLED1'].dropna(), 20) -fig, axes = plt.subplots(3, 3, figsize=(9, 9)) -for i, ax in zip(tc.keys(), axes.flatten()): - ax.imshow(tc[i], origin="lower", aspect="auto") - ax.set_title("Unit {}".format(i)) -axes[-1,-1].remove() -plt.tight_layout() - -# compute head direction. -diff = nwb['SpatialSeriesLED1'].values-nwb['SpatialSeriesLED2'].values -head_dir = np.arctan2(*diff.T) -head_dir = nap.Tsd(nwb['SpatialSeriesLED1'].index, head_dir) - -tune_head = nap.compute_1d_tuning_curves(nwb['units'], head_dir.dropna(), 30) - -fig, axes = plt.subplots(3, 3, figsize=(9, 9), subplot_kw={'projection': 'polar'}) -for i, ax in zip(tune_head.columns, axes.flatten()): - ax.plot(tune_head.index, tune_head[i]) - ax.set_title("Unit {}".format(i)) -axes[-1,-1].remove() - -# %% -# -# Okay, let's use unit number 7. -# -# Now let's set up our design matrix. First, let's fit the head direction by -# itself. Head direction is a circular variable (pi and -pi are adjacent to -# each other), so we need to use a basis that has this property as well. -# `CyclicBSplineBasis` is one such basis. -# -# Let's create our basis and then arrange our data properly. - -unit_no = 7 -spikes = nwb['units'][unit_no] - -basis = nmo.basis.CyclicBSplineBasis(10, order=5) -x = np.linspace(-np.pi, np.pi, 100) -plt.figure() -plt.plot(x, basis(x)) - -# Find the interval on which head_dir has no NaNs -head_dir = head_dir.dropna() -# Grab the second (of two), since the first one is really short -valid_data= head_dir.time_support.loc[[1]] -head_dir = head_dir.restrict(valid_data) -# Count spikes at the same rate as head direction, over the same epoch -spikes = spikes.count(bin_size=1/head_dir.rate, ep=valid_data) -# the time points for spike are in the middle of these bins (whereas for -# head_dir they're at the ends), so use interpolate to shift head_dir to the -# center. -head_dir = head_dir.interpolate(spikes) - -X = nmo.pytrees.FeaturePytree(head_direction=basis(head_dir)) - -# %% -# -# Now we'll fit our GLM and then see what our head direction tuning looks like: -model = nmo.glm.GLM(regularizer="Ridge", regularizer_strength=0.001) -model.fit(X, spikes) -print(model.coef_['head_direction']) - -bs_vis = basis(x) -tuning = jnp.einsum('b, tb->t', model.coef_['head_direction'], bs_vis) -plt.figure() -plt.polar(x, tuning) - -# %% -# -# This looks like a smoothed version of our tuning curve, like we'd expect! -# -# For a more direct comparison, we can plot the tuning function based on the model predicted -# firing rates with that estimated from the counts. - - -# predict rates and convert back to pynapple -rates_nap = nap.TsdFrame(t=head_dir.t, d=np.asarray(model.predict(X))) -# compute tuning function -tune_head_model = nap.compute_1d_tuning_curves_continuous(rates_nap, head_dir, 30) -# compare model prediction with data -fig, ax = plt.subplots(1, 1, subplot_kw={'projection': 'polar'}) -ax.plot(tune_head[7], label="counts") -# multiply by the sampling rate for converting to spike/sec. -ax.plot(tune_head_model * rates_nap.rate, label="model") - -# Let's compare this to using arrays, to see what it looks like: - -model = nmo.glm.GLM() -model.fit(X['head_direction'], spikes) -model.coef_ - -# %% -# -# We can see that the solution is identical, as is the way of interacting with -# the GLM object. -# -# However, with a single type of feature, it's unclear why exactly this is -# helpful. Let's add a feature for the animal's position in space. For this -# feature, we need a 2d basis. Let's use some raised cosine bumps and organize -# our data similarly. - -pos_basis = nmo.basis.RaisedCosineBasisLinear(10) * nmo.basis.RaisedCosineBasisLinear(10) -spatial_pos = nwb['SpatialSeriesLED1'].restrict(valid_data) - -X['spatial_position'] = pos_basis(*spatial_pos.values.T) - -# %% -# -# Running the GLM is identical to before, but we can see that our coef_ -# FeaturePytree now has two separate keys, one for each feature type. - -model = nmo.glm.GLM(solver_name="LBFGS") -model.fit(X, spikes) -model.coef_ - -# %% -# -# Let's visualize our tuning. Head direction looks pretty much the same (though -# the values are slightly different, as we can see when printing out the -# coefficients). - -bs_vis = basis(x) -tuning = jnp.einsum('b,nb->n', model.coef_['head_direction'], bs_vis) -print(model.coef_['head_direction']) -plt.figure() -plt.polar(x, tuning.T) - -# %% -# -# And the spatial tuning again looks like a smoothed version of our earlier -# tuning curves. -_, _, pos_bs_vis = pos_basis.evaluate_on_grid(50, 50) -pos_tuning = jnp.einsum('b,ijb->ij', model.coef_['spatial_position'], pos_bs_vis) -plt.figure() -plt.imshow(pos_tuning) - -# %% -# -# We could do all this with matrices as well, but we have to pay attention to -# indices in a way that is annoying: - -X_mat = nmo.utils.pynapple_concatenate_jax([X['head_direction'], X['spatial_position']], -1) - -model = nmo.glm.GLM() -model.fit(X_mat, spikes) -model.coef_[..., :basis.n_basis_funcs] diff --git a/docs/how_to_guide/plot_04_population_glm.py b/docs/how_to_guide/plot_04_population_glm.py deleted file mode 100644 index 70dac9cd..00000000 --- a/docs/how_to_guide/plot_04_population_glm.py +++ /dev/null @@ -1,185 +0,0 @@ -""" -# Population GLM - -Fitting the activity of a neural population with NeMoS can be much more efficient than fitting each individual -neuron in a loop. The reason for this is that NeMoS leverages the powerful GPU-vectorization implemented by `JAX`. - - -!!! note - For an unregularized, Lasso, Ridge, or group-Lasso GLM, fitting a GLM one neuron at the time, or fitting jointly - the neural population is equivalent. The main difference between the approaches is that the former is more - memory efficient, the latter is computationally more efficient (it takes less time to fit). - -## Fitting a Population GLM - -NeMoS has a dedicated `nemos.GLM.PopulationGLM` class for fitting jointly a neural population. The API - is very similar to that the regular `nemos.glm.GLM`, but with a few differences: - - 1. The `y` input to the methods `fit` and `score` must be a two-dimensional array of shape `(n_samples, n_neurons)`. - 2. You can optionally pass a `feature_mask` in the form of an array of 0s and 1s with shape `(n_features, n_neurons)` - that specifies which features are used as predictors for each neuron. More on this [later](#neuron-specific-features). - -Let's generate some synthetic data and fit a population model. -""" - -import jax.numpy as jnp -import matplotlib.pyplot as plt -import numpy as np - -import nemos as nmo - -np.random.seed(123) - -n_features = 5 -n_neurons = 2 -n_samples = 500 - -# random design array. Shape (n_time_points, n_features). -X = 0.5*np.random.normal(size=(n_samples, n_features)) - -# log-rates & weights -b_true = np.zeros((n_neurons, )) -w_true = np.random.uniform(size=(n_features, n_neurons)) - - -# generate counts (spikes will be (n_samples, n_features) -rate = jnp.exp(jnp.dot(X, w_true) + b_true) -spikes = np.random.poisson(rate) - -print(spikes.shape) - -# %% -# We can now instantiate the `PopulationGLM` model and fit. -model = nmo.glm.PopulationGLM() -model.fit(X, spikes) - -print(f"population GLM log-likelihood: {model.score(X, spikes)}") - -# %% -# ## Neuron-specific features -# If you want to model neurons with different input features, the way to do so is to specify a `feature_mask`. -# Let's assume that we have two neurons, share one shared input, and have an extra private one, for a total of -# 3 inputs. - -# let's take the first three input -n_features = 3 -input_features = X[:, :3] - - -# %% -# Let's assume that: -# -# - `input_features[:, 0]` is shared. -# - `input_features[:, 1]` is an input only for the first neuron. -# - `input_features[:, 2]` is an input only for the second neuron. -# -# We can simulate this scenario, - -# model the rate of the first neuron using only the first two features and weights. -rate_neuron_1 = jnp.exp(np.dot(input_features[:, [0, 1]], w_true[: 2, 0])) - -# model the rate of the second neuron using only the first and last feature and weights. -rate_neuron_2 = jnp.exp(np.dot(input_features[:, [0, 2]], w_true[[0, 2], 1])) - -# stack the rates in a (n_samples, n_neurons) array and generate spikes -rate = np.hstack((rate_neuron_1[:, np.newaxis], rate_neuron_2[:, np.newaxis])) -spikes = np.random.poisson(rate) - -# %% -# We can impose the same constraint to the `PopulationGLM` by masking the weights. - -# initialize the mask to a matrix of 1s. -feature_mask = np.ones((n_features, n_neurons)) - -# remove the 3rd feature from the predictors of the first neuron -feature_mask[2, 0] = 0 - -# remove the 2nd feature from the predictors of the second neuron -feature_mask[1, 1] = 0 - -# visualize the mask -print(feature_mask) - -# %% -# The mask can be passed at initialization or set after the model is initialized, but cannot be changed -# after the model is fit. - -# set a quasi-newton solver and low tolerance for better numerical precision -model = nmo.glm.PopulationGLM(solver_name="LBFGS", solver_kwargs={"tol": 10**-12}) - -# set the mask -model.feature_mask = feature_mask - -# fit the model -model.fit(input_features, spikes) - -# %% -# If we print the model coefficients, we can see the effect of the mask. - -print(model.coef_) - -# %% -# The coefficient for the first neuron corresponding to the last feature is zero, as well as -# the coefficient of the second neuron corresponding to the second feature. -# -# To convince ourselves that this is equivalent to fit each neuron individually with the correct features, -# let's go ahead and try. - -# features for each neuron -features_by_neuron = { - 0: [0, 1], - 1: [0, 2] -} -# initialize the coefficients -coeff = np.zeros((2, 2)) - -# loop over the neurons and fit a GLM -for neuron in range(2): - model_neu = nmo.glm.GLM( - solver_name="LBFGS", solver_kwargs={"tol":10**-12} - ) - model_neu.fit(input_features[:, features_by_neuron[neuron]], spikes[:, neuron]) - coeff[:, neuron] = model_neu.coef_ - -# visually compare the estimated coeffeicients -fig, axs = plt.subplots(1, 2, figsize=(6, 3)) -for neuron in range(2): - axs[neuron].set_title(f"neuron {neuron}") - axs[neuron].bar([0, 4], w_true[features_by_neuron[neuron], neuron], width=0.8, label="true") - axs[neuron].bar([1, 5], coeff[:, neuron], width=0.8, label="single neuron GLM") - axs[neuron].bar([2, 6], model.coef_[features_by_neuron[neuron], neuron], width=0.8, label="population GLM") - axs[neuron].set_ylabel("coefficient") - axs[neuron].set_ylim(0, 0.8) - axs[neuron].set_xticks([0.5, 3.5]) - axs[neuron].set_xticklabels(["feature 0", f"feature {neuron + 1}"]) - if neuron == 1: - plt.legend() -plt.tight_layout() - -# %% -# ## FeaturePytree -# `PopulationGLM` is compatible with [`FeaturePytree`](../plot_03_glm_pytree). If you structured your predictors -# in a `FeaturePytree`, the `feature_mask` needs to be a dictionary of the same structure, containing arrays -# of shape `(n_neurons, )`. -# The example above can be reformulated as follows, - -# restructure the input as FeaturePytree -pytree_features = nmo.pytrees.FeaturePytree( - shared=input_features[:, :1], - neu_0=input_features[:, 1:2], - neu_1=input_features[:, 2:] -) - -# Define a mask as a dictionary -pytree_mask = dict( - shared=np.array([1, 1]), - neu_0=np.array([1, 0]), - neu_1=np.array([0, 1]) -) - -# fit a model -model_tree = nmo.glm.PopulationGLM(solver_name="LBFGS", feature_mask=pytree_mask) -model_tree.fit(pytree_features, spikes) - -# print the coefficients -print(model_tree.coef_) diff --git a/docs/how_to_guide/plot_05_batch_glm.py b/docs/how_to_guide/plot_05_batch_glm.py deleted file mode 100644 index 7454d6f1..00000000 --- a/docs/how_to_guide/plot_05_batch_glm.py +++ /dev/null @@ -1,200 +0,0 @@ -""" -# Batching example - -Here we demonstrate how to setup and run a stochastic gradient descent in `nemos` -by batching and using the `update` method of the model class. - -""" - -import matplotlib.pyplot as plt -import numpy as np -import pynapple as nap - -import nemos as nmo - -nap.nap_config.suppress_conversion_warnings = True - -# set random seed -np.random.seed(123) - -# %% -# ## Simulate data -# -# Let's generate some data artificially -n_neurons = 10 -T = 50 - -times = np.linspace(0, T, 5000).reshape(-1, 1) -rate = np.exp(np.sin(times + np.linspace(0, np.pi*2, n_neurons).reshape(1, n_neurons))) - -# %% -# Get the spike times from the rate and generate a `TsGroup` object -spike_t, spike_id = np.where(np.random.poisson(rate)) -units = nap.Tsd(spike_t/T, spike_id).to_tsgroup() - - -# %% -# ## Model configuration -# -# Let's imagine this dataset do not fit in memory. We can use a batching approach to train the GLM. -# First we need to instantiate the `PopulationGLM`. The default algorithm for `PopulationGLM` is gradient descent. -# We suggest to use it for batching. -# -# !!! Note -# You must shutdown the dynamic update of the step for fitting a batched (also called stochastic) gradient descent. -# In jaxopt, this can be done by setting the parameters `acceleration` to False and setting the `stepsize`. -# -glm = nmo.glm.PopulationGLM( - solver_name="GradientDescent", - solver_kwargs={"stepsize": 0.1, "acceleration": False} - ) - -# %% -# ## Basis instantiation -# -# Here we instantiate the basis with a window size of 40 time bins. It corresponds to a 200ms windows -# for a 5ms bin size. -basis = nmo.basis.RaisedCosineBasisLog(5, mode="conv", window_size=40) - -# %% -# ## Batch definition -# -# The batch size needs to be larger than the window size of the convolution kernel defined above. -batch_size = 5 # second - - -# %% -# Here we define a batcher function that generate a random 5 s of design matrix and spike counts. -# This function will be called during each iteration of the stochastic gradient descent. -def batcher(): - # Grab a random time within the time support. Here is the time support is one epoch only so it's easy. - t = np.random.uniform(units.time_support[0, 0], units.time_support[0, 1]-batch_size) - - # Bin the spike train in a 1s batch - ep = nap.IntervalSet(t, t+batch_size) - counts = units.restrict(ep).count(0.005) # count in 5 ms bins - - # Convolve - X = basis.compute_features(counts) - - # Return X and counts - return X, counts - - -# %% -# ## Solver initialization -# -# First we need to initialize the gradient descent solver within the `PopulationGLM`. -# This gets you the initial parameters and the first state of the solver. -params = glm.initialize_params(*batcher()) -state = glm.initialize_state(*batcher(), params) - -# %% -# ## Batch learning -# -# Let's do a few iterations of gradient descent calling the `batcher` function at every step. -# At each step, we store the log-likelihood of the model for each neuron evaluated on the batch -n_step = 500 -logl = np.zeros(n_step) - -for i in range(n_step): - - # Get a batch of data - X, Y = batcher() - - # Do one step of gradient descent. - params, state = glm.update(params, state, X, Y) - - # Score the model along the time axis - logl[i] = glm.score(X, Y, score_type="log-likelihood") - - -# %% -# -# !!! Warning "Input validation" -# The `update` method does not perform input validation each time it is called. -# This design choice speeds up computation by avoiding repetitive checks. However, -# it requires that all inputs to the `update` method strictly conform to the expected -# dimensionality and structure as established during the initialization of the solver. -# Failure to comply with these expectations will likely result in runtime errors or -# incorrect computations. -# -# First let's plot the log-likelihood to see if the model is converging. - -plt.figure() -plt.plot(logl) -plt.xlabel("Iteration") -plt.ylabel("Log-likelihood") -plt.show() - - -# %% -# We can see that the log-likelihood is increasing but did not reach plateau yet. -# The number of iterations can be increased to continue learning. -# -# We can take a look at the coefficients. -# Here we extract the weight matrix of shape `(n_neurons*n_basis, n_neurons)` -# and reshape it to `(n_neurons, n_basis, n_neurons)`. -# We then average along basis to get a weight matrix of shape `(n_neurons, n_neurons)`. - -W = glm.coef_.reshape(len(units), basis.n_basis_funcs, len(units)) -Wm = np.mean(np.abs(W), 1) - -# Let's plot it. - -plt.figure() -plt.imshow(Wm) -plt.xlabel("Neurons") -plt.ylabel("Neurons") -plt.show() - -# %% -# ## Model comparison -# -# Since this example is small enough, we can fit the full model and compare the scores. -# Here we generate the design matrix and spike counts for the whole dataset. -Y = units.count(0.005) -X = basis.compute_features(Y) -full_model = nmo.glm.PopulationGLM().fit(X, Y) - -# %% -# Now that the full model is fitted, we are scoring the full model and the batch model against the full datasets to compare the scores. -# The score is pseudo-R2 -full_scores = full_model.score( - X, Y, aggregate_sample_scores=lambda x:np.mean(x, axis=0), score_type="pseudo-r2-McFadden" -) -batch_scores = glm.score( - X, Y, aggregate_sample_scores=lambda x:np.mean(x, axis=0), score_type="pseudo-r2-McFadden" -) - -# %% -# Let's compare scores for each neurons as well as the coefficients. - -plt.figure(figsize=(10, 8)) -gs = plt.GridSpec(3,2) -plt.subplot(gs[0,:]) -plt.bar(np.arange(0, n_neurons), full_scores, 0.4, label="Full model") -plt.bar(np.arange(0, n_neurons)+0.5, batch_scores, 0.4, label="Batch model") -plt.ylabel("Pseudo R2") -plt.xlabel("Neurons") -plt.ylim(0, 1) -plt.legend() -plt.subplot(gs[1:,0]) -plt.imshow(Wm) -plt.title("Batch model") -plt.subplot(gs[1:,1]) -Wm2 = np.mean( - np.abs( - full_model.coef_.reshape(len(units), basis.n_basis_funcs, len(units)) - ) - , 1) -plt.imshow(Wm2) -plt.title("Full model") -plt.tight_layout() -plt.show() - -# %% -# As we can see, with a few iterations, the batch model manage to recover a similar coefficient matrix. - - - diff --git a/docs/how_to_guide/plot_06_sklearn_pipeline_cv_demo.py b/docs/how_to_guide/plot_06_sklearn_pipeline_cv_demo.py deleted file mode 100644 index ca9b167a..00000000 --- a/docs/how_to_guide/plot_06_sklearn_pipeline_cv_demo.py +++ /dev/null @@ -1,506 +0,0 @@ -""" -# Selecting basis by cross-validation with scikit-learn - -In this demo, we will demonstrate how to select an appropriate basis and its hyperparameters using cross-validation. -In particular, we will learn: - -1. What a scikit-learn pipeline is. -2. Why pipelines are useful. -3. How to combine NeMoS `Basis` and `GLM` objects in a pipeline. -4. How to select the number of bases and the basis type through cross-validation (or any other hyperparameter in the pipeline). -5. How to use a custom scoring metric to quantify the performance of each configuration. - -""" - -# %% -# ## What is a scikit-learn pipeline -# -#
-# Pipeline illustration. -#
Schematic of a scikit-learn pipeline.
-#
-# -# A pipeline is a sequence of data transformations leading up to a model. Each step before the final one transforms the input data into a different representation, and then the final model step fits, predicts, or scores based on the previous step's output and some observations. Setting up such machinery can be simplified using the `Pipeline` class from scikit-learn. -# -# To set up a scikit-learn `Pipeline`, ensure that: -# -# 1. Each intermediate step is a [scikit-learn transformer object](https://scikit-learn.org/stable/data_transforms.html) with a `transform` and/or `fit_transform` method. -# 2. The final step is an [estimator object](https://scikit-learn.org/stable/developers/develop.html#estimators) with a `fit` method, or a model with `fit`, `predict`, and `score` methods. -# -# Each transformation step takes a 2D array `X` of shape `(num_samples, num_original_features)` as input and outputs another 2D array of shape `(num_samples, num_transformed_features)`. The final step takes a pair `(X, y)`, where `X` is as before, and `y` is a 1D array of shape `(n_samples,)` containing the observations to be modeled. -# -# You can define a pipeline as follows: -# ```python -# from sklearn.pipeline import Pipeline -# -# # Assume transformer_i/predictor is a transformer/model object -# pipe = Pipeline( -# [ -# ("label_1", transformer_1), -# ("label_2", transformer_2), -# ..., -# ("label_n", transformer_n), -# ("label_model", model) -# ] -# ) -# ``` -# -# Note that you have to assign a label to each step of the pipeline. -# !!! tip -# Here we used a placeholder `"label_i"` for demonstration; you should choose a more descriptive name depending on the type of transformation step. -# -# Calling `pipe.fit(X, y)` will perform the following computations: -# ```python -# # Chain of transformations -# X1 = transformer_1.fit_transform(X) -# X2 = transformer_2.fit_transform(X1) -# # ... -# Xn = transformer_n.fit_transform(Xn_1) -# -# # Fit step -# model.fit(Xn, y) -# ``` -# And the same holds for `pipe.score` and `pipe.predict`. -# -# ## Why pipelines are useful -# -# Pipelines not only streamline and simplify your code but also offer several other advantages. The real power of pipelines becomes evident when combined with the scikit-learn `model_selection` module, which includes cross-validation and similar methods. This combination allows you to tune hyperparameters at each step of the pipeline in a straightforward manner. -# -# In the following sections, we will showcase this approach with a concrete example: selecting the appropriate basis type and number of bases for a GLM regression in NeMoS. -# -# ## Combining basis transformations and GLM in a pipeline -# Let's start by creating some toy data. - -import matplotlib.pyplot as plt -import numpy as np -import pandas as pd -import scipy.stats -import seaborn as sns -from sklearn.model_selection import GridSearchCV -from sklearn.pipeline import Pipeline - -import nemos as nmo - -# some helper plotting functions -from nemos import _documentation_utils as doc_plots - -# predictors, shape (n_samples, n_features) -X = np.random.uniform(low=0, high=1, size=(1000, 1)) -# observed counts, shape (n_samples,) -rate = 2 * ( - scipy.stats.norm.pdf(X, scale=0.1, loc=0.25) - + scipy.stats.norm.pdf(X, scale=0.1, loc=0.75) -) -y = np.random.poisson(rate).astype(float).flatten() - -# %% -# Let's now plot the simulated neuron's tuning curve, which is bimodal, Gaussian-shaped, and has peaks at 0.25 and 0.75. - -# %% -fig, ax = plt.subplots() -ax.scatter(X.flatten(), y, alpha=0.2) -ax.set_xlabel("input") -ax.set_ylabel("spike count") -sns.despine(ax=ax) - -# %% -# ### Converting NeMoS `Basis` to a transformer -# In order to use NeMoS `Basis` in a pipeline, we need to convert it into a scikit-learn transformer. This can be achieved through the `TransformerBasis` wrapper class. -# -# Instantiating a `TransformerBasis` can be done either using the constructor directly or with `Basis.to_transformer()`: - -# %% -bas = nmo.basis.RaisedCosineBasisLinear(5, mode="conv", window_size=5) -# these two ways of creating the TransformerBasis are equivalent -trans_bas_a = nmo.basis.TransformerBasis(bas) -trans_bas_b = bas.to_transformer() - -# %% -# `TransformerBasis` provides convenient access to the underlying `Basis` object's attributes: - -# %% -print(bas.n_basis_funcs, trans_bas_a.n_basis_funcs, trans_bas_b.n_basis_funcs) - -# %% -# We can also set attributes of the underlying `Basis`. Note that -- because `TransformerBasis` is created with a copy of the `Basis` object passed to it -- this does not change the original `Basis`, and neither does changing the original `Basis` change `TransformerBasis` we created: - -# %% -trans_bas_a.n_basis_funcs = 10 -bas.n_basis_funcs = 100 - -print(bas.n_basis_funcs, trans_bas_a.n_basis_funcs, trans_bas_b.n_basis_funcs) - -# %% -# ### Creating and fitting a pipeline -# We might want to combine first transforming the input data with our basis functions, then fitting a GLM on the transformed data. -# -# This is exactly what `Pipeline` is for! - -# %% -pipeline = Pipeline( - [ - ( - "transformerbasis", - nmo.basis.TransformerBasis(nmo.basis.RaisedCosineBasisLinear(6)), - ), - ( - "glm", - nmo.glm.GLM(regularizer_strength=0.5, regularizer="Ridge"), - ), - ] -) - -pipeline.fit(X, y) - -# %% -# Note how NeMoS models are already scikit-learn compatible and can be used directly in the pipeline. -# -# Visualize the fit: - -# %% - -# Predict the rate. -# Note that you need a 2D input even if x is a flat array. -# We are using expand dim to add the extra-dimension -x = np.sort(X, axis=0) -predicted_rate = pipeline.predict(x) - -# %% -fig, ax = plt.subplots() - -ax.scatter(X.flatten(), y, alpha=0.2, label="generated spike counts") -ax.set_xlabel("input") -ax.set_ylabel("spike count") - - -ax.plot( - x, - predicted_rate, - label="predicted rate", - color="tab:orange", -) - -ax.legend() -sns.despine(ax=ax) - -# %% -# The current model captures the bimodal distribution of responses, appropriately picking out the peaks. However, it doesn't do a good job capturing the actual firing rate: the peaks are too low and the valleys are not low enough. This might be because of our choice of basis and/or regularizer strength, so let's see if tuning those parameters results in a better fit! We could do this manually, but doing this with the sklearn pipeline will make everything much easier! - -# %% -# ### Select the number of basis by cross-validation - -# %% -# !!! warning -# Please keep in mind that while `GLM.score` supports different ways of evaluating goodness-of-fit through the `score_type` argument, `pipeline.score(X, y, score_type="...")` does not propagate this, and uses the default value of `log-likelihood`. -# -# To evaluate a pipeline, please create a custom scorer (e.g. `pseudo_r2` below) and call `my_custom_scorer(pipeline, X, y)`. -# -# #### Define the parameter grid -# -# Let's define candidate values for the parameters of each step of the pipeline we want to cross-validate. In this case the number of basis functions in the transformation step and the ridge regularization's strength in the GLM fit: - -# %% -param_grid = dict( - glm__regularizer_strength=(0.1, 0.01, 0.001, 1e-6), - transformerbasis__n_basis_funcs=(3, 5, 10, 20, 100), -) - -# %% -# !!! note "Grid definition" -# In order to define a parameter grid dictionary for a pipeline, you must structure the dictionary keys as follows: -# -# - Start with the pipeline label (`"glm"` or `"transformerbasis"` for us). This determines which pipeline step has the relevant hyperparameter. -# - Add `"__"` followed by the hyperparameter name (for example, `"n_basis_funcs"`). -# - If the hyperparameter is itself an object with attributes, add another `"__"` followed by the attribute name. For instance, `"glm__observation_model__inverse_link_function"` -# would be a valid key for cross-validating over the link function of the GLM's `observation_model` attribute `inverse_link_function`. -# The values in the dictionary are the parameters to be tested. - - - -# %% -# #### Run the grid search -# Let's run a 5-fold cross-validation of the hyperparameters with the scikit-learn `model_selection.GridsearchCV` class. -# ??? info "K-Fold cross-validation" -#

-# Grid Search Cross Validation -#
-# K-fold cross-validation (modified from scikit-learn docs) -#

-# K-fold cross-validation is a robust method used for selecting hyperparameters. In this procedure, the data is divided into K equally sized chunks (or folds). The model is trained on K-1 of these chunks, with the remaining chunk used for evaluation. This process is repeated K times, with each chunk being used exactly once as the evaluation set. -# After completing the K iterations, the K evaluation scores are averaged to provide a reliable estimate of the model's performance. To select the optimal hyperparameters, K-fold cross-validation can be applied over a grid of potential hyperparameters, with the set yielding the highest average score being chosen as the best. - - -# %% -gridsearch = GridSearchCV( - pipeline, - param_grid=param_grid, - cv=5 -) - -# run the 5-fold cross-validation grid search -gridsearch.fit(X, y) - -# %% -# -# ??? note "Manual cross-validation" -# To appreciate how much boiler-plate code we are saving by calling scikit-learn cross-validation, below -# we can see how this cross-validation will look like in a manual loop. -# -# ```python -# from itertools import product -# from copy import deepcopy -# -# regularizer_strength = (0.1, 0.01, 0.001, 1e-6) -# n_basis_funcs = (3, 5, 10, 20, 100) -# -# # define the folds -# n_folds = 5 -# fold_idx = np.arange(X.shape[0] - X.shape[0] % n_folds).reshape(n_folds, -1) -# -# -# # Initialize the scores -# scores = np.zeros((len(regularizer_strength) * len(n_basis_funcs), n_folds)) -# -# # Dictionary to store coefficients -# coeffs = {} -# -# # initialize basis and model -# basis = nmo.basis.TransformerBasis(nmo.basis.RaisedCosineBasisLinear(6)) -# model = nmo.glm.GLM(regularizer="Ridge") -# -# # loop over combinations -# for fold in range(n_folds): -# test_idx = fold_idx[fold] -# train_idx = fold_idx[[x for x in range(n_folds) if x != fold]].flatten() -# for i, params in enumerate(product(regularizer_strength, n_basis_funcs)): -# reg_strength, n_basis = params -# -# # deepcopy the basis and model -# bas = deepcopy(basis) -# glm = deepcopy(model) -# -# # set the parameters -# bas.n_basis_funcs = n_basis -# glm.regularizer_strength = reg_strength -# -# # fit the model -# glm.fit(bas.transform(X[train_idx]), y[train_idx]) -# -# # store score and coefficients -# scores[i, fold] = glm.score(bas.transform(X[test_idx]), y[test_idx]) -# coeffs[(i, fold)] = (glm.coef_, glm.intercept_) -# -# # get the best mean test score -# i_best = np.argmax(scores.mean(axis=1)) -# # get the overall best coeffs -# fold_best = np.argmax(scores[i_best]) -# -# # set up the best model -# model.coef_ = coeffs[(i_best, fold_best)][0] -# model.intercept_ = coeffs[(i_best, fold_best)][1] -# -# # get the best hyperparameters -# best_reg_strength = regularizer_strength[i_best // len(n_basis_funcs)] -# best_n_basis = n_basis_funcs[i_best % len(n_basis_funcs)] -# ``` - -# %% -# #### Visualize the scores -# -# Let's extract the scores from `gridsearch` and take a look at how the different parameter values of our pipeline influence the test score: - - -cvdf = pd.DataFrame(gridsearch.cv_results_) - -cvdf_wide = cvdf.pivot( - index="param_transformerbasis__n_basis_funcs", - columns="param_glm__regularizer_strength", - values="mean_test_score", -) - -doc_plots.plot_heatmap_cv_results(cvdf_wide) - -# %% -# The plot displays the model's log-likelihood for each parameter combination in the grid. The parameter combination with the highest score, which is the one selected by the procedure, is highlighted with a blue rectangle. We can thus see that we need 10 or more basis functions, and that all of the tested regularization strengths agree with each other. In general, we want the fewest number of basis functions required to get a good fit, so we'll choose 10 here. -# -# #### Visualize the predicted rate -# Finally, visualize the predicted firing rates using the best model found by our grid-search, which gives a better fit than the randomly chosen parameter values we tried in the beginning: - -# %% - -# Predict the ate using the best configuration, -x = np.sort(X, axis=0) -predicted_rate = gridsearch.best_estimator_.predict(x) - -# %% -fig, ax = plt.subplots() - -ax.scatter(X.flatten(), y, alpha=0.2, label="generated spike counts") -ax.set_xlabel("input") -ax.set_ylabel("spike count") - - -ax.plot( - x, - predicted_rate, - label="predicted rate", - color="tab:orange", -) - -ax.legend() -sns.despine(ax=ax) - -# %% -# :rocket::rocket::rocket: **Success!** :rocket::rocket::rocket: -# We are now able to capture the distribution of the firing rate appropriately: both peaks and valleys in the spiking activity are matched by our model predicitons. -# -# ### Evaluating different bases directly -# -# In the previous example we set the number of basis functions of the `Basis` wrapped in our `TransformerBasis`. However, if we are for example not sure about the type of basis functions we want to use, or we have already defined some basis functions of our own, then we can use cross-validation to directly evaluate those as well. -# -# Here we include `transformerbasis___basis` in the parameter grid to try different values for `TransformerBasis._basis`: - -# %% -param_grid = dict( - glm__regularizer_strength=(0.1, 0.01, 0.001, 1e-6), - transformerbasis___basis=( - nmo.basis.RaisedCosineBasisLinear(5), - nmo.basis.RaisedCosineBasisLinear(10), - nmo.basis.RaisedCosineBasisLog(5), - nmo.basis.RaisedCosineBasisLog(10), - nmo.basis.MSplineBasis(5), - nmo.basis.MSplineBasis(10), - ), -) - -# %% -# Then run the grid search: - -# %% -gridsearch = GridSearchCV( - pipeline, - param_grid=param_grid, - cv=5, -) - -# run the 5-fold cross-validation grid search -gridsearch.fit(X, y) - - -# %% -# Wrangling the output data a bit and looking at the scores: - -# %% -cvdf = pd.DataFrame(gridsearch.cv_results_) - -# Read out the number of basis functions -cvdf["transformerbasis_config"] = [ - f"{b.__class__.__name__} - {b.n_basis_funcs}" - for b in cvdf["param_transformerbasis___basis"] -] - -cvdf_wide = cvdf.pivot( - index="transformerbasis_config", - columns="param_glm__regularizer_strength", - values="mean_test_score", -) - -doc_plots.plot_heatmap_cv_results(cvdf_wide) - - -# %% -# As shown in the table, the model with the highest score, highlighted in blue, used a RaisedCosineBasisLinear basis (as used above), which appears to be a suitable choice for our toy data. -# We can confirm that by plotting the firing rate predictions: - -# Predict the rate using the optimal configuration -x = np.sort(X, axis=0) -predicted_rate = gridsearch.best_estimator_.predict(x) - -# %% -fig, ax = plt.subplots() - -ax.scatter(X.flatten(), y, alpha=0.2, label="generated spike counts") -ax.set_xlabel("input") -ax.set_ylabel("spike count") - -ax.plot( - x, - predicted_rate, - label="predicted rate", - color="tab:orange", -) - -ax.legend() -sns.despine(ax=ax) - -# %% -# The plot confirms that the firing rate distribution is accurately captured by our model predictions. - -# %% -# !!! warning -# Please note that because it would lead to unexpected behavior, mixing the two ways of defining values for the parameter grid is not allowed. The following would lead to an error: -# -# ```python -# param_grid = dict( -# glm__regularizer_strength=(0.1, 0.01, 0.001, 1e-6), -# transformerbasis__n_basis_funcs=(3, 5, 10, 20, 100), -# transformerbasis___basis=( -# nmo.basis.RaisedCosineBasisLinear(5), -# nmo.basis.RaisedCosineBasisLinear(10), -# nmo.basis.RaisedCosineBasisLog(5), -# nmo.basis.RaisedCosineBasisLog(10), -# nmo.basis.MSplineBasis(5), -# nmo.basis.MSplineBasis(10), -# ), -# ) -# ``` - -# %% -# ## Create a custom scorer -# By default, the GLM score method returns the model log-likelihood. If you want to try a different metric, such as the pseudo-R2, you can create a custom scorer and pass it to the cross-validation object: - -# %% -from sklearn.metrics import make_scorer - -pseudo_r2 = make_scorer( - nmo.observation_models.PoissonObservations().pseudo_r2 -) - -# %% -# We can now run the grid search providing the custom scorer - -# %% -gridsearch = GridSearchCV( - pipeline, - param_grid=param_grid, - cv=5, - scoring=pseudo_r2, -) - -# Run the 5-fold cross-validation grid search -gridsearch.fit(X, y) - -# %% -# And finally, we can plot each model's score. - -# %% -# Plot the pseudo-R2 scores -cvdf = pd.DataFrame(gridsearch.cv_results_) - -# Read out the number of basis functions -cvdf["transformerbasis_config"] = [ - f"{b.__class__.__name__} - {b.n_basis_funcs}" - for b in cvdf["param_transformerbasis___basis"] -] - -cvdf_wide = cvdf.pivot( - index="transformerbasis_config", - columns="param_glm__regularizer_strength", - values="mean_test_score", -) - -doc_plots.plot_heatmap_cv_results(cvdf_wide, label="pseudo-R2") - -# %% -# As you can see, the results with pseudo-R2 agree with those of the negative log-likelihood. Note that this new metric is normalized between 0 and 1, with a higher score indicating better performance. - diff --git a/docs/tutorials/plot_01_current_injection.py b/docs/tutorials/plot_01_current_injection.py deleted file mode 100644 index 0e54ffeb..00000000 --- a/docs/tutorials/plot_01_current_injection.py +++ /dev/null @@ -1,691 +0,0 @@ -# -*- coding: utf-8 -*- - -"""# Fit injected current - -For our first example, we will look at a very simple dataset: patch-clamp -recordings from a single neuron in layer 4 of mouse primary visual cortex. This -data is from the [Allen Brain -Atlas](https://celltypes.brain-map.org/experiment/electrophysiology/478498617), -and experimenters injected current directly into the cell, while recording the -neuron's membrane potential and spiking behavior. The experiments varied the -shape of the current across many sweeps, mapping the neuron's behavior in -response to a wide range of potential inputs. - -For our purposes, we will examine only one of these sweeps, "Noise 1", in which -the experimentalists injected three pulses of current. The current is a square -pulse multiplied by a sinusoid of a fixed frequency, with some random noise -riding on top. - -![Allen Brain Atlas view of the data we will analyze.](../../assets/allen_data.png) - -In the figure above (from the Allen Brain Atlas website), we see the -approximately 22 second sweep, with the input current plotted in the first row, -the intracellular voltage in the second, and the recorded spikes in the third. -(The grey lines and dots in the second and third rows comes from other sweeps -with the same stimulus, which we'll ignore in this exercise.) When fitting the -Generalized Linear Model, we are attempting to model the spiking behavior, and -we generally do not have access to the intracellular voltage, so for the rest -of this notebook, we'll use only the input current and the recorded spikes -displayed in the first and third rows. - -First, let us see how to load in the data and reproduce the above figure, which -we'll do using the [Pynapple package](https://pynapple-org.github.io/pynapple/). We will rely on -pynapple throughout this notebook, as it simplifies handling this type of -data (we will explain the essentials of pynapple as they are used, but see the -[Pynapple docs](https://pynapple-org.github.io/pynapple/) -if you are interested in learning more). After we've explored the data some, we'll introduce the Generalized -Linear Model and how to fit it with NeMoS. - -## Learning objectives {.keep-text} - -- Learn how to explore spiking data and do basic analyses using pynapple -- Learn how to structure data for NeMoS -- Learn how to fit a basic Generalized Linear Model using NeMoS -- Learn how to retrieve the parameters and predictions from a fit GLM for - intrepetation. - -""" - - - -# Import everything -import jax -import matplotlib.pyplot as plt -import numpy as np -import pynapple as nap - -import nemos as nmo - -# some helper plotting functions -from nemos import _documentation_utils as doc_plots - -# configure plots some -plt.style.use(nmo.styles.plot_style) - -# %% -# ## Data Streaming -# -# While you can download the data directly from the Allen Brain Atlas and -# interact with it using their -# [AllenSDK](https://allensdk.readthedocs.io/en/latest/visual_behavior_neuropixels.html), -# we prefer the burgeoning [Neurodata Without Borders (NWB) -# standard](https://nwb-overview.readthedocs.io/en/latest/). We have converted -# this single dataset to NWB and uploaded it to the [Open Science -# Framework](https://osf.io/5crqj/). This allows us to easily load the data -# using pynapple, and it will immediately be in a format that pynapple understands! -# -# !!! tip -# -# Pynapple can stream any NWB-formatted dataset! See [their -# documentation](https://pynapple.org/examples/tutorial_pynapple_dandi.html) -# for more details, and see the [DANDI Archive](https://dandiarchive.org/) -# for a repository of compliant datasets. -# -# The first time the following cell is run, it will take a little bit of time -# to download the data, and a progress bar will show the download's progress. -# On subsequent runs, the cell gets skipped: we do not need to redownload the -# data. - - -path = nmo.fetch.fetch_data("allen_478498617.nwb") - -# %% -# ## Pynapple -# -# ### Data structures and preparation -# -# Now that we've downloaded the data, let's open it with pynapple and examine -# its contents. - - -data = nap.load_file(path) -print(data) - -# %% -# -# The dataset contains several different pynapple objects, which we will -# explore throughout this demo. The following illustrates how these fields relate to the data -# we visualized above: -# -# ![Annotated view of the data we will analyze.](../../assets/allen_data_annotated.gif) -# -# -# - `units`: dictionary of neurons, holding each neuron's spike timestamps. -# - `epochs`: start and end times of different intervals, defining the -# experimental structure, specifying when each stimulation protocol began and -# ended. -# - `stimulus`: injected current, in Amperes, sampled at 20k Hz. -# - `response`: the neuron's intracellular voltage, sampled at 20k Hz. -# We will not use this info in this example -# -# Now let's go through the relevant variables in some more detail: - - -trial_interval_set = data["epochs"] - -current = data["stimulus"] -spikes = data["units"] - -# %% -# First, let's examine `trial_interval_set`: - - -trial_interval_set.keys() - -# %% -# -# `trial_interval_set` is a dictionary with strings for keys and -# [`IntervalSets`](https://pynapple.org/generated/pynapple.core.interval_set.IntervalSet.html) -# for values. Each key defines the stimulus protocol, with the value defining -# the beginning and end of that stimulation protocol. - -noise_interval = trial_interval_set["Noise 1"] -noise_interval - -# %% -# -# As described above, we will be examining "Noise 1". We can see it contains -# three rows, each defining a separate sweep. We'll just grab the first sweep -# (shown in blue in the pictures above) and ignore the other two (shown in -# gray). - -noise_interval = noise_interval[0] -noise_interval - -# %% -# -# Now let's examine `current`: - -current - -# %% -# -# `current` is a `Tsd` -# ([TimeSeriesData](https://pynapple.org/generated/pynapple.core.time_series.Tsd.html)) -# object with 2 columns. Like all `Tsd` objects, the first column contains the -# time index and the second column contains the data; in this case, the current -# in Ampere (A). -# -# Currently, `current` contains the entire ~900 second experiment but, as -# discussed above, we only want one of the "Noise 1" sweeps. Fortunately, -# `pynapple` makes it easy to grab out the relevant time points by making use -# of the `noise_interval` we defined above: - - -current = current.restrict(noise_interval) -# convert current from Ampere to pico-amperes, to match the above visualization -# and move the values to a more reasonable range. -current = current * 1e12 -current - -# %% -# -# Notice that the timestamps have changed and our shape is much smaller. -# -# Finally, let's examine the spike times. `spikes` is a -# [`TsGroup`](https://pynapple.org/generated/pynapple.core.ts_group.TsGroup.html#pynapple.core.ts_group.TsGroup), -# a dictionary-like object that holds multiple `Ts` (timeseries) objects with -# potentially different time indices: - - -spikes - -# %% -# -# Typically, this is used to hold onto the spike times for a population of -# neurons. In this experiment, we only have recordings from a single neuron, so -# there's only one row. -# -# We can index into the `TsGroup` to see the timestamps for this neuron's -# spikes: - - -spikes[0] - -# %% -# -# Similar to `current`, this object originally contains data from the entire -# experiment. To get only the data we need, we again use -# `restrict(noise_interval)`: - -spikes = spikes.restrict(noise_interval) -print(spikes) -spikes[0] - - -# %% -# -# Now, let's visualize the data from this trial, replicating rows 1 and 3 -# from the Allen Brain Atlas figure at the beginning of this notebook: - - -fig, ax = plt.subplots(1, 1, figsize=(8, 2)) -ax.plot(current, "grey") -ax.plot(spikes.to_tsd([-5]), "|", color="k", ms = 10) -ax.set_ylabel("Current (pA)") -ax.set_xlabel("Time (s)") - -# %% -# -# ### Basic analyses -# -# Before using the Generalized Linear Model, or any model, it's worth taking -# some time to examine our data and think about what features are interesting -# and worth capturing. As we discussed in the [background](../../background/plot_00_conceptual_intro), -# the GLM is a model of the neuronal firing rate. However, in our experiments, -# we do not observe the firing rate, only the spikes! Moreover, neural -# responses are typically noisy—even in this highly controlled experiment -# where the same current was injected over multiple trials, the spike times -# were slightly different from trial-to-trial. No model can perfectly predict -# spike times on an individual trial, so how do we tell if our model is doing a -# good job? -# -# Our objective function is the log-likelihood of the observed spikes given the -# predicted firing rate. That is, we're trying to find the firing rate, as a -# function of time, for which the observed spikes are likely. Intuitively, this -# makes sense: the firing rate should be high where there are many spikes, and -# vice versa. However, it can be difficult to figure out if your model is doing -# a good job by squinting at the observed spikes and the predicted firing rates -# plotted together. -# -# One common way to visualize a rough estimate of firing rate is to smooth -# the spikes by convolving them with a Gaussian filter. -# -# !!! info -# -# This is a heuristic for getting the firing rate, and shouldn't be taken -# as the literal truth (to see why, pass a firing rate through a Poisson -# process to generate spikes and then smooth the output to approximate the -# generating firing rate). A model should not be expected to match this -# approximate firing rate exactly, but visualizing the two firing rates -# together can help you reason about which phenomena in your data the model -# is able to adequately capture, and which it is missing. -# -# For more information, see section 1.2 of [*Theoretical -# Neuroscience*](https://boulderschool.yale.edu/sites/default/files/files/DayanAbbott.pdf), -# by Dayan and Abbott. -# -# Pynapple can easily compute this approximate firing rate, and plotting this -# information will help us pull out some phenomena that we think are -# interesting and would like a model to capture. -# -# First, we must convert from our spike times to binned spikes: - -# bin size in seconds -bin_size = 0.001 -# Get spikes for neuron 0 -count = spikes[0].count(bin_size) -count - -# %% -# -# Now, let's convert the binned spikes into the firing rate, by smoothing them -# with a gaussian kernel. Pynapple again provides a convenience function for -# this: - -# the inputs to this function are the standard deviation of the gaussian in seconds and -# the full width of the window, in standard deviations. So std=.05 and size_factor=20 -# gives a total filter size of 0.05 sec * 20 = 1 sec. -firing_rate = count.smooth(std=0.05, size_factor=20) -# convert from spikes per bin to spikes per second (Hz) -firing_rate = firing_rate / bin_size - -# %% -# -# Note that firing_rate is a [`TsdFrame`](https://pynapple.org/generated/pynapple.core.time_series.TsdFrame.html)! -# - -print(type(firing_rate)) - -# %% -# -# Now that we've done all this preparation, let's make a plot to more easily -# visualize the data. -# -# !!! note -# -# We're hiding the details of the plotting function for the purposes of this -# tutorial, but you can find it in [the source -# code](https://github.com/flatironinstitute/nemos/blob/development/src/nemos/_documentation_utils/plotting.py) -# if you are interested. - -doc_plots.current_injection_plot(current, spikes, firing_rate) - -# %% -# -# So now that we can view the details of our experiment a little more clearly, -# what do we see? -# -# - We have three intervals of increasing current, and the firing rate -# increases as the current does. -# -# - While the neuron is receiving the input, it does not fire continuously or -# at a steady rate; there appears to be some periodicity in the response. The -# neuron fires for a while, stops, and then starts again. There's periodicity -# in the input as well, so this pattern in the response might be reflecting -# that. -# -# - There's some decay in firing rate as the input remains on: there are three -# four "bumps" of neuronal firing in the second and third intervals and they -# decrease in amplitude, with first being the largest. -# -# These give us some good phenomena to try and predict! But there's something -# that's not quite obvious from the above plot: what is the relationship -# between the input and the firing rate? As described in the first bullet point -# above, it looks to be *monotonically increasing*: as the current increases, -# so does the firing rate. But is that exactly true? What form is that -# relationship? -# -# Pynapple can compute a tuning curve to help us answer this question, by -# binning our spikes based on the instantaneous input current and computing the -# firing rate within those bins: -# -# !!! note "Tuning curve in `pynapple`" -# [`compute_1d_tuning_curves`](https://pynapple.org/generated/pynapple.process.tuning_curves.html#pynapple.process.tuning_curves.compute_1d_tuning_curves) : compute the firing rate as a function of a 1-dimensional feature. - -tuning_curve = nap.compute_1d_tuning_curves(spikes, current, nb_bins=15) -tuning_curve - -# %% -# -# `tuning_curve` is a pandas DataFrame where each column is a neuron (one -# neuron in this case) and each row is a bin over the feature (here, the input -# current). We can easily plot the tuning curve of the neuron: - -doc_plots.tuning_curve_plot(tuning_curve) - -# %% -# -# We can see that, while the firing rate mostly increases with the current, -# it's definitely not a linear relationship, and it might start decreasing as -# the current gets too large. -# -# So this gives us three interesting phenomena we'd like our model to help -# explain: the tuning curve between the firing rate and the current, the firing -# rate's periodicity, and the gradual reduction in firing rate while the -# current remains on. - -# %% -# ## NeMoS {.strip-code} -# -# ### Preparing data -# -# Now that we understand our model, we're almost ready to put it together. -# Before we construct it, however, we need to get the data into the right -# format. -# -# NeMoS requires that the predictors and spike counts it operates on have the -# following properties: -# -# - predictors and spike counts must have the same number of time points. -# -# - predictors must be two-dimensional, with shape `(n_time_bins, n_features)`. -# In this example, we have a single feature (the injected current). -# -# - spike counts must be one-dimensional, with shape `(n_time_bins, )`. As -# discussed above, `n_time_bins` must be the same for both the predictors and -# spike counts. -# -# - predictors and spike counts must be -# [`jax.numpy`](https://jax.readthedocs.io/en/latest/jax-101/01-jax-basics.html) -# arrays, `numpy` arrays or `pynapple` `TsdFrame`/`Tsd`. -# -# !!! info "What is jax?" -# -# [jax](https://github.com/google/jax) is a Google-supported python library -# for automatic differentiation. It has all sorts of neat features, but the -# most relevant of which for NeMoS is its GPU-compatibility and -# just-in-time compilation (both of which make code faster with little -# overhead!), as well as the collection of optimizers present in -# [jaxopt](https://jaxopt.github.io/stable/). -# -# First, we require that our predictors and our spike counts have the same -# number of time bins. We can achieve this by down-sampling our current to the -# spike counts to the proper resolution using the -# [`bin_average`](https://pynapple.org/generated/pynapple.core.time_series.Tsd.bin_average.html#pynapple.core.time_series.Tsd.bin_average) -# method from pynapple: - -binned_current = current.bin_average(bin_size) - -print(f"current shape: {binned_current.shape}") -# rate is in Hz, convert to KHz -print(f"current sampling rate: {binned_current.rate/1000.:.02f} KHz") - -print(f"\ncount shape: {count.shape}") -print(f"count sampling rate: {count.rate/1000:.02f} KHz") - - -# %% -# -# Secondly, we have to reshape our variables so that they are the proper shape: -# -# - `predictors`: `(n_time_bins, n_features)` -# - `count`: `(n_time_bins, )` -# -# Because we only have a single predictor feature, we'll use -# [`np.expand_dims`](https://numpy.org/doc/stable/reference/generated/numpy.expand_dims.html) -# to ensure it is a 2d array. - -predictor = np.expand_dims(binned_current, 1) - -# check that the dimensionality matches NeMoS expectation -print(f"predictor shape: {predictor.shape}") -print(f"count shape: {count.shape}") - -# %% -# !!! info "What if I have more than one neuron?" -# -# In this example, we're only fitting data for a single neuron, but you -# might wonder how the data should be shaped if you have more than one -# neuron -- do you add an extra dimension? or concatenate neurons along one -# of the existing dimensions? -# -# In NeMoS, we always fit Generalized Linear Models to a single neuron at a -# time. We'll discuss this more in the [following -# tutorial](../plot_02_head_direction/), but briefly: you get the same answer -# whether you fit the neurons separately or simultaneously, and fitting -# them separately can make your life easier. -# -# ### Fitting the model -# -# Now we're ready to fit our model! -# -# First, we need to define our GLM model object. We intend for users -# to interact with our models like -# [scikit-learn](https://scikit-learn.org/stable/getting_started.html) -# estimators. In a nutshell, a model instance is initialized with -# hyperparameters that specify optimization and model details, -# and then the user calls the `.fit()` function to fit the model to data. -# We will walk you through the process below by example, but if you -# are interested in reading more details see the [Getting Started with scikit-learn](https://scikit-learn.org/stable/getting_started.html) webpage. -# -# To initialize our model, we need to specify the regularizer and observation -# model objects, both of which should be one of our custom objects: -# -# - Regularizer: this object specifies both the solver algorithm and the -# regularization scheme. They are jointly specified because each -# regularization scheme has a list of compatible solvers to choose between. -# Regularization modifies the objective function to reflect your prior -# beliefs about the parameters, such as sparsity. Regularization becomes more -# important as the number of input features, and thus model parameters, -# grows. They can be found within `nemos.regularizer`. -# -# !!! warning -# -# With a convex problem like the GLM, in theory it does not matter which -# solver algorithm you use. In practice, due to numerical issues, it -# generally does. Thus, it's worth trying a couple to see how their -# solutions compare. (Different regularization schemes will always give -# different results.) -# -# - Observation model: this object links the firing rate and the observed -# data (in this case spikes), describing the distribution of neural activity (and thus changing -# the log-likelihood). For spiking data, we use the Poisson observation model, but -# we discuss other options for continuous data -# in [the calcium imaging analysis demo](../plot_06_calcium_imaging/). -# -# For this example, we'll use an un-regularized LBFGS solver. We'll discuss -# regularization in a later tutorial. -# -# !!! info "Why LBFGS?" -# -# [LBFGS](https://en.wikipedia.org/wiki/Limited-memory_BFGS) is a -# quasi-Netwon method, that is, it uses the first derivative (the gradient) -# and approximates the second derivative (the Hessian) in order to solve -# the problem. This means that LBFGS tends to find a solution faster and is -# often less sensitive to step-size. Try other solvers to see how they -# behave! -# - -# Initialize the model w/regularizer and solver -model = nmo.glm.GLM(solver_name="LBFGS") - -# %% -# -# Now that we've initialized our model with the optimization parameters, we can -# fit our data! In the previous section, we prepared our model matrix -# (`predictor`) and target data (`count`), so to fit the model we just need to -# pass them to the model: - -model.fit(predictor, count) - -# %% -# -# Now that we've fit our data, we can retrieve the resulting parameters. -# Similar to scikit-learn, these are stored as the `coef_` and `intercept_` -# attributes: - -print(f"firing_rate(t) = exp({model.coef_} * current(t) + {model.intercept_})") - -# %% -# -# Note that `model.coef_` has shape `(n_features, )`, while `model.intercept_` -# is a scalar: - -print(f"coef_ shape: {model.coef_.shape}") -print(f"intercept_ shape: {model.intercept_.shape}") - -# %% -# -# It's nice to get the parameters above, but we can't tell how well our model -# is doing by looking at them. So how should we evaluate our model? -# -# First, we can use the model to predict the firing rates and compare that to -# the smoothed spike train. By calling `predict()` we can get the model's -# predicted firing rate for this data. Note that this is just the output of the -# model's linear-nonlinear step, as described earlier! - -# mkdocs_gallery_thumbnail_number = 4 - -predicted_fr = model.predict(predictor) -# convert units from spikes/bin to spikes/sec -predicted_fr = predicted_fr / bin_size - - -# and let's smooth the firing rate the same way that we smoothed the firing rate -smooth_predicted_fr = predicted_fr.smooth(0.05, size_factor=20) - -# and plot! -doc_plots.current_injection_plot(current, spikes, firing_rate, - # plot the predicted firing rate that has - # been smoothed the same way as the - # smoothed spike train - predicted_firing_rate=smooth_predicted_fr) - -# %% -# -# What do we see above? Note that the y-axes in the final row are different for -# each subplot! -# -# - Predicted firing rate increases as injected current goes up — Success! :tada: -# -# - The amplitude of the predicted firing rate only matches the observed -# amplitude in the third interval: it's too high in the first and too low in -# the second — Failure! :x: -# -# - Our predicted firing rate has the periodicity we see in the smoothed spike -# train — Success! :tada: -# -# - The predicted firing rate does not decay as the input remains on: the -# amplitudes are identical for each of the bumps within a given interval — -# Failure! :x: -# -# The failure described in the second point may seem particularly confusing — -# approximate amplitude feels like it should be very easy to capture, so what's -# going on? -# -# To get a better sense, let's look at the mean firing rate over the whole -# period: - -# compare observed mean firing rate with the model predicted one -print(f"Observed mean firing rate: {np.mean(count) / bin_size} Hz") -print(f"Predicted mean firing rate: {np.mean(predicted_fr)} Hz") - -# %% -# -# We matched the average pretty well! So we've matched the average and the -# range of inputs from the third interval reasonably well, but overshot at low -# inputs and undershot in the middle. -# -# We can see this more directly by computing the tuning curve for our predicted -# firing rate and comparing that against our smoothed spike train from the -# beginning of this notebook. Pynapple can help us again with this: - -tuning_curve_model = nap.compute_1d_tuning_curves_continuous(predicted_fr[:, np.newaxis], current, 15) -fig = doc_plots.tuning_curve_plot(tuning_curve) -fig.axes[0].plot(tuning_curve_model, color="tomato", label="glm") -fig.axes[0].legend() - -# %% -# -# In addition to making that mismatch discussed earlier a little more obvious, -# this tuning curve comparison also highlights that this model thinks the -# firing rate will continue to grow as the injected current increases, which is -# not reflected in the data. -# -# Viewing this plot also makes it clear that the model's tuning curve is -# approximately exponential. We already knew that! That's what it means to be a -# LNP model of a single input. But it's nice to see it made explicit. -# -# ### Finishing up -# -# There are a handful of other operations you might like to do with the GLM. -# First, you might be wondering how to simulate spikes — the GLM is a LNP -# model, but the firing rate is just the output of *LN*, its first two steps. -# The firing rate is just the mean of a Poisson process, so we can pass it to -# `jax.random.poisson`: - -spikes = jax.random.poisson(jax.random.PRNGKey(123), predicted_fr.values) - -# %% -# -# Note that this is not actually that informative and, in general, it is -# recommended that you focus on firing rates when interpreting your model. -# -# Also, while -# including spike history is often helpful, it can sometimes make simulations unstable: -# if your GLM includes auto-regressive inputs (e.g., neurons are -# connected to themselves or each other), simulations can sometimes can behave -# poorly because of runaway excitation [$^{[1, 2]}$](#ref-1). -# -# Finally, you may want a number with which to evaluate your model's -# performance. As discussed earlier, the model optimizes log-likelihood to find -# the best-fitting weights, and we can calculate this number using its `score` -# method: - -log_likelihood = model.score(predictor, count, score_type="log-likelihood") -print(f"log-likelihood: {log_likelihood}") - -# %% -# -# This log-likelihood is un-normalized and thus doesn't mean that much by -# itself, other than "higher=better". When comparing alternative GLMs fit on -# the same dataset, whether that's models using different regularizers and -# solvers or those using different predictors, comparing log-likelihoods is a -# reasonable thing to do. -# -# !!! info -# -# Under the hood, NeMoS is minimizing the negative log-likelihood, as is -# typical in many optimization contexts. `score` returns the real -# log-likelihood, however, and thus higher is better. -# -# Because it's un-normalized, however, the log-likelihood should not be -# compared across datasets (because e.g., it won't account for difference in -# noise levels). We provide the ability to compute the pseudo-$R^2$ for this -# purpose: -model.score(predictor, count, score_type='pseudo-r2-Cohen') - -# %% -# ## Citation -# -# The data used in this tutorial is from the **Allen Brain Map**, with the -# [following -# citation](https://knowledge.brain-map.org/data/1HEYEW7GMUKWIQW37BO/summary): -# -# **Contributors:** Agata Budzillo, Bosiljka Tasic, Brian R. Lee, Fahimeh -# Baftizadeh, Gabe Murphy, Hongkui Zeng, Jim Berg, Nathan Gouwens, Rachel -# Dalley, Staci A. Sorensen, Tim Jarsky, Uygar Sümbül Zizhen Yao -# -# **Dataset:** Allen Institute for Brain Science (2020). Allen Cell Types Database -# -- Mouse Patch-seq [dataset]. Available from -# brain-map.org/explore/classes/multimodal-characterization. -# -# **Primary publication:** Gouwens, N.W., Sorensen, S.A., et al. (2020). Integrated -# morphoelectric and transcriptomic classification of cortical GABAergic cells. -# Cell, 183(4), 935-953.E19. https://doi.org/10.1016/j.cell.2020.09.057 -# -# **Patch-seq protocol:** Lee, B. R., Budzillo, A., et al. (2021). Scaled, high -# fidelity electrophysiological, morphological, and transcriptomic cell -# characterization. eLife, 2021;10:e65482. https://doi.org/10.7554/eLife.65482 -# -# **Mouse VISp L2/3 glutamatergic neurons:** Berg, J., Sorensen, S. A., Miller, J., -# Ting, J., et al. (2021) Human neocortical expansion involves glutamatergic -# neuron diversification. Nature, 598(7879):151-158. doi: -# 10.1038/s41586-021-03813-8 -# -# ## References -# -# [1] Arribas, Diego, Yuan Zhao, and Il Memming Park. "Rescuing neural spike train models from bad MLE." Advances in Neural Information Processing Systems 33 (2020): 2293-2303. -# -# [2] Hocker, David, and Memming Park. "Multistep inference for generalized linear spiking models curbs runaway excitation." International IEEE/EMBS Conference on Neural Engineering, May 2017. diff --git a/docs/tutorials/plot_02_head_direction.py b/docs/tutorials/plot_02_head_direction.py deleted file mode 100644 index dc4740d0..00000000 --- a/docs/tutorials/plot_02_head_direction.py +++ /dev/null @@ -1,603 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -# Fit head-direction population - -## Learning objectives - -- Learn how to add history-related predictors to NeMoS GLM -- Learn about NeMoS `Basis` objects -- Learn how to use `Basis` objects with convolution - -""" - -import matplotlib.pyplot as plt -import numpy as np -import pynapple as nap - -import nemos as nmo - -# some helper plotting functions -from nemos import _documentation_utils as doc_plots - -# configure pynapple to ignore conversion warning -nap.nap_config.suppress_conversion_warnings = True - -# configure plots some -plt.style.use(nmo.styles.plot_style) - -# %% -# ## Data Streaming -# -# Here we load the data from OSF. The data is a NWB file. - -path = nmo.fetch.fetch_data("Mouse32-140822.nwb") - -# %% -# ## Pynapple -# We are going to open the NWB file with pynapple. - - -data = nap.load_file(path) - -data - -# %% -# -# Get spike timings - - -spikes = data["units"] - -spikes - -# %% -# -# Get the behavioural epochs (in this case, sleep and wakefulness) -# - - -epochs = data["epochs"] -wake_ep = data["epochs"]["wake"] - -# %% -# Get the tracked orientation of the animal - - -angle = data["ry"] - - -# %% -# This cell will restrict the data to what we care about i.e. the activity of head-direction neurons during wakefulness. -# - -spikes = spikes.getby_category("location")["adn"] - -spikes = spikes.restrict(wake_ep).getby_threshold("rate", 1.0) -angle = angle.restrict(wake_ep) - -# %% -# First let's check that they are head-direction neurons. - - -tuning_curves = nap.compute_1d_tuning_curves( - group=spikes, feature=angle, nb_bins=61, minmax=(0, 2 * np.pi) -) - -# %% -# Each row indicates an angular bin (in radians), and each column corresponds to a single unit. -# Let's plot the tuning curve of the first two neurons. - -fig, ax = plt.subplots(1, 2, figsize=(12, 4)) -ax[0].plot(tuning_curves.iloc[:, 0]) -ax[0].set_xlabel("Angle (rad)") -ax[0].set_ylabel("Firing rate (Hz)") -ax[1].plot(tuning_curves.iloc[:, 1]) -ax[1].set_xlabel("Angle (rad)") -plt.tight_layout() - -# %% -# Before using NeMoS, let's explore the data at the population level. -# -# Let's plot the preferred heading -# - -fig = doc_plots.plot_head_direction_tuning( - tuning_curves, spikes, angle, threshold_hz=1, start=8910, end=8960 -) - -# %% -# As we can see, the population activity tracks very well the current head-direction of the animal. -# **Question : are neurons constantly tuned to head-direction and can we use it to predict the spiking activity of each neuron based only on the activity of other neurons?** -# -# To fit the GLM faster, we will use only the first 3 min of wake - - -wake_ep = nap.IntervalSet( - start=wake_ep.start[0], end=wake_ep.start[0] + 3 * 60 -) - -# %% -# To use the GLM, we need first to bin the spike trains. Here we use pynapple - -bin_size = 0.01 -count = spikes.count(bin_size, ep=wake_ep) - -# %% -# Here we are going to rearrange neurons order based on their prefered directions. -# - - -pref_ang = tuning_curves.idxmax() - -count = nap.TsdFrame( - t=count.t, - d=count.values[:, np.argsort(pref_ang.values)], -) - -# %% -# ## NeMoS {.strip-code} -# It's time to use NeMoS. Our goal is to estimate the pairwise interaction between neurons. -# This can be quantified with a GLM if we use the recent population spike history to predict the current time step. -# ### Self-Connected Single Neuron -# To simplify our life, let's see first how we can model spike history effects in a single neuron. -# The simplest approach is to use counts in fixed length window $i$, $y_{t-i}, \dots, y_{t-1}$ to predict the next -# count $y_{t}$. Let's plot the count history, -# - - -# select a neuron's spike count time series -neuron_count = count[:, 0] - -# restrict to a smaller time interval -epoch_one_spk = nap.IntervalSet( - start=count.time_support.start[0], end=count.time_support.start[0] + 1.2 -) -plt.figure(figsize=(8, 3.5)) -plt.step( - neuron_count.restrict(epoch_one_spk).t, neuron_count.restrict(epoch_one_spk).d, where="post" -) -plt.title("Spike Count Time Series") -plt.xlabel("Time (sec)") -plt.ylabel("Counts") -plt.tight_layout() - -# %% -# #### Features Construction -# Let's fix the spike history window size that we will use as predictor. - - -# set the size of the spike history window in seconds -window_size_sec = 0.8 - -doc_plots.plot_history_window(neuron_count, epoch_one_spk, window_size_sec) - - -# %% -# For each time point, we shift our window one bin at the time and vertically stack the spike count history in a matrix. -# Each row of the matrix will be used as the predictors for the rate in the next bin (red narrow rectangle in -# the figure). - - -doc_plots.run_animation(neuron_count, epoch_one_spk.start[0]) - -# %% -# If $t$ is smaller than the window size, we won't have a full window of spike history for estimating the rate. -# One may think of padding the window (with zeros for example) but this may generate weird border artifacts. -# To avoid that, we can simply restrict our analysis to times $t$ larger than the window and NaN-pad earlier -# time-points; -# -# A fast way to compute this feature matrix is convolving the counts with the identity matrix. -# We can apply the convolution and NaN-padding in a single step using the -# [`nemos.convolve.create_convolutional_predictor`](../../../reference/nemos/convolve/#nemos.convolve.create_convolutional_predictor) -# function. - -# convert the prediction window to bins (by multiplying with the sampling rate) -window_size = int(window_size_sec * neuron_count.rate) - -# convolve the counts with the identity matrix. -plt.close("all") -input_feature = nmo.convolve.create_convolutional_predictor( - np.eye(window_size), neuron_count -) - -# print the NaN indices along the time axis -print("NaN indices:\n", np.where(np.isnan(input_feature[:, 0]))[0]) - -# %% -# The binned counts originally have shape "number of samples", we should check that the -# dimension are matching our expectation - -print(f"Time bins in counts: {neuron_count.shape[0]}") -print(f"Convolution window size in bins: {window_size}") -print(f"Feature shape: {input_feature.shape}") - -# %% -# -# We can visualize the output for a few time bins - - -suptitle = "Input feature: Count History" -neuron_id = 0 -doc_plots.plot_features(input_feature, count.rate, suptitle) - -# %% -# As you may see, the time axis is backward, this happens because convolution flips the time axis. -# This is equivalent, as we can interpret the result as how much a spike will affect the future rate. -# In the previous tutorial our feature was 1-dimensional (just the current), now -# instead the feature dimension is 80, because our bin size was 0.01 sec and the window size is 0.8 sec. -# We can learn these weights by maximum likelihood by fitting a GLM. - -# %% -# #### Fitting the Model -# -# When working a real dataset, it is good practice to train your models on a chunk of the data and -# use the other chunk to assess the model performance. This process is known as "cross-validation". -# There is no unique strategy on how to cross-validate your model; What works best -# depends on the characteristic of your data (time series or independent samples, -# presence or absence of trials...), and that of your model. Here, for simplicity use the first -# half of the wake epochs for training and the second half for testing. This is a reasonable -# choice if the statistics of the neural activity does not change during the course of -# the recording. We will learn about better cross-validation strategies with other -# examples. - -# construct the train and test epochs -duration = input_feature.time_support.tot_length("s") -start = input_feature.time_support["start"] -end = input_feature.time_support["end"] -first_half = nap.IntervalSet(start, start + duration / 2) -second_half = nap.IntervalSet(start + duration / 2, end) - -# %% -# Fit the glm to the first half of the recording and visualize the ML weights. - - -# define the GLM object -model = nmo.glm.GLM(solver_name="LBFGS") - -# Fit over the training epochs -model.fit( - input_feature.restrict(first_half), - neuron_count.restrict(first_half) -) - -# %% - -plt.figure() -plt.title("Spike History Weights") -plt.plot(np.arange(window_size) / count.rate, np.squeeze(model.coef_), lw=2, label="GLM raw history 1st Half") -plt.axhline(0, color="k", lw=0.5) -plt.xlabel("Time From Spike (sec)") -plt.ylabel("Kernel") -plt.legend() - -# %% -# The response in the previous figure seems noise added to a decay, therefore the response -# can be described with fewer degrees of freedom. In other words, it looks like we -# are using way too many weights to describe a simple response. -# If we are correct, what would happen if we re-fit the weights on the other half of the data? -# #### Inspecting the results - -# fit on the test set - -model_second_half = nmo.glm.GLM(solver_name="LBFGS") -model_second_half.fit( - input_feature.restrict(second_half), - neuron_count.restrict(second_half) -) - -plt.figure() -plt.title("Spike History Weights") -plt.plot(np.arange(window_size) / count.rate, np.squeeze(model.coef_), - label="GLM raw history 1st Half", lw=2) -plt.plot(np.arange(window_size) / count.rate, np.squeeze(model_second_half.coef_), - color="orange", label="GLM raw history 2nd Half", lw=2) -plt.axhline(0, color="k", lw=0.5) -plt.xlabel("Time From Spike (sec)") -plt.ylabel("Kernel") -plt.legend() - -# %% -# What can we conclude? -# -# The fast fluctuations are inconsistent across fits, indicating that -# they are probably capturing noise, a phenomenon known as over-fitting; -# On the other hand, the decaying trend is fairly consistent, even if -# our estimate is noisy. You can imagine how things could get -# worst if we needed a finer temporal resolution, such 1ms time bins -# (which would require 800 coefficients instead of 80). -# What can we do to mitigate over-fitting now? -# -# #### Reducing feature dimensionality -# One way to proceed is to find a lower-dimensional representation of the response -# by parametrizing the decay effect. For instance, we could try to model it -# with an exponentially decaying function $f(t) = \exp( - \alpha t)$, with -# $\alpha >0$ a positive scalar. This is not a bad idea, because we would greatly -# simplify the dimensionality our features (from 80 to 1). Unfortunately, -# there is no way to know a-priori what is a good parameterization. More -# importantly, not all the parametrizations guarantee a unique and stable solution -# to the maximum likelihood estimation of the coefficients (convexity). -# -# In the GLM framework, the main way to construct a lower dimensional parametrization -# while preserving convexity, is to use a set of basis functions. -# For history-type inputs, whether of the spiking history or of the current -# history, we'll use the raised cosine log-stretched basis first described in -# [Pillow et al., 2005](https://www.jneurosci.org/content/25/47/11003). This -# basis set has the nice property that their precision drops linearly with -# distance from event, which is a makes sense for many history-related inputs -# in neuroscience: whether an input happened 1 or 5 msec ago matters a lot, -# whereas whether an input happened 51 or 55 msec ago is less important. - - -doc_plots.plot_basis() - -# %% -# !!! info -# -# We provide a handful of different choices for basis functions, and -# selecting the proper basis function for your input is an important -# analytical step. We will eventually provide guidance on this choice, but -# for now we'll give you a decent choice. -# -# NeMoS includes `Basis` objects to handle the construction and use of these -# basis functions. -# -# When we instantiate this object, the only arguments we need to specify is the -# number of functions we want, the mode of operation of the basis (`"conv"`), -# and the window size for the convolution. With more basis functions, we'll be able to -# represent the effect of the corresponding input with the higher precision, at -# the cost of adding additional parameters. - -# a basis object can be instantiated in "conv" mode for convolving the input. -basis = nmo.basis.RaisedCosineBasisLog( - n_basis_funcs=8, mode="conv", window_size=window_size -) - -# `basis.evaluate_on_grid` is a convenience method to view all basis functions -# across their whole domain: -time, basis_kernels = basis.evaluate_on_grid(window_size) - -print(basis_kernels.shape) - -# time takes equi-spaced values between 0 and 1, we could multiply by the -# duration of our window to scale it to seconds. -time *= window_size_sec - -# %% -# To appreciate why the raised-cosine basis can approximate well our response -# we can learn a "good" set of weight for the basis element such that -# a weighted sum of the basis approximates the GLM weights for the count history. -# One way to do so is by minimizing the least-squares. - - -# compute the least-squares weights -lsq_coef, _, _, _ = np.linalg.lstsq(basis_kernels, np.squeeze(model.coef_), rcond=-1) - -# plot the basis and the approximation -doc_plots.plot_weighted_sum_basis(time, model.coef_, basis_kernels, lsq_coef) - -# %% -# -# The first plot is the response of each of the 8 basis functions to a single -# pulse. This is known as the impulse response function, and is a useful way to -# characterize linear systems like our basis objects. The second plot are is a -# bar plot representing the least-square coefficients. The third one are the -# impulse responses scaled by the weights. The last plot shows the sum of the -# scaled response overlapped to the original spike count history weights. -# -# Our predictor previously was huge: every possible 80 time point chunk of the -# data, for 1440000 total numbers. By using this basis set we can instead reduce -# the predictor to 8 numbers for every 80 time point window for 144000 total -# numbers. Basically an order of magnitude less. With 1ms bins we would have -# achieved 2 order of magnitude reduction in input size. This is a huge benefit -# in terms of memory allocation and, computing time. As an additional benefit, -# we will reduce over-fitting. -# -# Let's see our basis in action. We can "compress" spike history feature by convolving the basis -# with the counts (without creating the large spike history feature matrix). -# This can be performed in NeMoS by calling the "compute_features" method of basis. - - -# equivalent to -# `nmo.convolve.create_convolutional_predictor(basis_kernels, neuron_count)` -conv_spk = basis.compute_features(neuron_count) - -print(f"Raw count history as feature: {input_feature.shape}") -print(f"Compressed count history as feature: {conv_spk.shape}") - -# Visualize the convolution results -epoch_one_spk = nap.IntervalSet(8917.5, 8918.5) -epoch_multi_spk = nap.IntervalSet(8979.2, 8980.2) - -doc_plots.plot_convolved_counts(neuron_count, conv_spk, epoch_one_spk, epoch_multi_spk) - -# find interval with two spikes to show the accumulation, in a second row - -# %% -# Now that we have our "compressed" history feature matrix, we can fit the ML parameters for a GLM. - -# %% -# #### Fit and compare the models - -# use restrict on interval set training -model_basis = nmo.glm.GLM(solver_name="LBFGS") -model_basis.fit(conv_spk.restrict(first_half), neuron_count.restrict(first_half)) - -# %% -# We can plot the resulting response, noting that the weights we just learned needs to be "expanded" back -# to the original `window_size` dimension by multiplying them with the basis kernels. -# We have now 8 coefficients, - -print(model_basis.coef_) - -# %% -# In order to get the response we need to multiply the coefficients by their corresponding -# basis function, and sum them. - -self_connection = np.matmul(basis_kernels, np.squeeze(model_basis.coef_)) - -print(self_connection.shape) - -# %% -# We can now compare this model that based on the raw count history. - -plt.figure() -plt.title("Spike History Weights") -plt.plot(time, np.squeeze(model.coef_), alpha=0.3, label="GLM raw history") -plt.plot(time, self_connection, "--k", label="GLM basis", lw=2) -plt.axhline(0, color="k", lw=0.5) -plt.xlabel("Time from spike (sec)") -plt.ylabel("Weight") -plt.legend() - -# %% -# Let's check if our new estimate does a better job in terms of over-fitting. We can do that -# by visual comparison, as we did previously. Let's fit the second half of the dataset. - -model_basis_second_half = nmo.glm.GLM(solver_name="LBFGS") -model_basis_second_half.fit(conv_spk.restrict(second_half), neuron_count.restrict(second_half)) - -# compute responses for the 2nd half fit -self_connection_second_half = np.matmul(basis_kernels, np.squeeze(model_basis_second_half.coef_)) - -plt.figure() -plt.title("Spike History Weights") -plt.plot(time, np.squeeze(model.coef_), "k", alpha=0.3, label="GLM raw history 1st half") -plt.plot(time, np.squeeze(model_second_half.coef_), alpha=0.3, color="orange", label="GLM raw history 2nd half") -plt.plot(time, self_connection, "--k", lw=2, label="GLM basis 1st half") -plt.plot(time, self_connection_second_half, color="orange", lw=2, ls="--", label="GLM basis 2nd half") -plt.axhline(0, color="k", lw=0.5) -plt.xlabel("Time from spike (sec)") -plt.ylabel("Weight") -plt.legend() - - -# %% -# Or we can score the model predictions using both one half of the set for training -# and the other half for testing. - -# compare model scores, as expected the training score is better with more parameters -# this may could be over-fitting. -print(f"full history train score: {model.score(input_feature.restrict(first_half), neuron_count.restrict(first_half), score_type='pseudo-r2-Cohen')}") -print(f"basis train score: {model_basis.score(conv_spk.restrict(first_half), neuron_count.restrict(first_half), score_type='pseudo-r2-Cohen')}") - -# %% -# To check that, let's try to see ho the model perform on unseen data and obtaining a test -# score. -print(f"\nfull history test score: {model.score(input_feature.restrict(second_half), neuron_count.restrict(second_half), score_type='pseudo-r2-Cohen')}") -print(f"basis test score: {model_basis.score(conv_spk.restrict(second_half), neuron_count.restrict(second_half), score_type='pseudo-r2-Cohen')}") - -# %% -# Let's extract and plot the rates - - -rate_basis = model_basis.predict(conv_spk) * conv_spk.rate -rate_history = model.predict(input_feature) * conv_spk.rate -ep = nap.IntervalSet(start=8819.4, end=8821) - -# plot the rates -doc_plots.plot_rates_and_smoothed_counts( - neuron_count, - {"Self-connection raw history":rate_history, "Self-connection bsais": rate_basis} -) - -# %% -# ### All-to-all Connectivity -# The same approach can be applied to the whole population. Now the firing rate of a neuron -# is predicted not only by its own count history, but also by the rest of the -# simultaneously recorded population. We can convolve the basis with the counts of each neuron -# to get an array of predictors of shape, `(num_time_points, num_neurons * num_basis_funcs)`. -# -# #### Preparing the features - -# define a basis function that expects an input of shape (num_samples, num_neurons). -num_neurons = count.shape[1] -basis = nmo.basis.RaisedCosineBasisLog( - n_basis_funcs=8, mode="conv", window_size=window_size, label="convolved counts" -) - -# convolve all the neurons -convolved_count = basis.compute_features(count) - -# %% -# Check the dimension to make sure it make sense -# Shape should be (n_samples, n_basis_func * num_neurons) -print(f"Convolved count shape: {convolved_count.shape}") - -# %% -# #### Fitting the Model -# This is an all-to-all neurons model. -# We are using the class `PopulationGLM` to fit the whole population at once. -# -# !!! note -# Once we condition on past activity, log-likelihood of the population is the sum of the log-likelihood -# of individual neurons. Maximizing the sum (i.e. the population log-likelihood) is equivalent to -# maximizing each individual term separately (i.e. fitting one neuron at the time). -# - -model = nmo.glm.PopulationGLM( - regularizer="Ridge", - solver_name="LBFGS", - regularizer_strength=0.1 - ).fit(convolved_count, count) - -# %% -# #### Comparing model predictions. -# Predict the rate (counts are already sorted by tuning prefs) - -predicted_firing_rate = model.predict(convolved_count) * conv_spk.rate - -# %% -# Plot fit predictions over a short window not used for training. - -# use pynapple for time axis for all variables plotted for tick labels in imshow -doc_plots.plot_head_direction_tuning_model(tuning_curves, predicted_firing_rate, spikes, angle, threshold_hz=1, - start=8910, end=8960, cmap_label="hsv") -# %% -# Let's see if our firing rate predictions improved and in what sense. - -# mkdocs_gallery_thumbnail_number = 2 -doc_plots.plot_rates_and_smoothed_counts( - neuron_count, - {"Self-connection: raw history": rate_history, - "Self-connection: bsais": rate_basis, - "All-to-all: basis": predicted_firing_rate[:, 0]} -) - -# %% -# #### Visualizing the connectivity -# Compute the tuning curve form the predicted rates. - -tuning = nap.compute_1d_tuning_curves_continuous(predicted_firing_rate, - feature=angle, - nb_bins=61, - minmax=(0, 2 * np.pi)) - -# %% -# Extract the weights and store it in a (n_neurons, n_basis_funcs, n_neurons) array. -# We can use `basis.split_by_feature` for this. The method will return a dictionary with an array -# for each feature, and keys the label we provided to the basis. -# In this case, "convolved counts" is the only feature. - -# split the coefficients by feature -weights = basis.split_by_feature(model.coef_, axis=0) - -# the output is a dictionary containing an array of shape (n_neurons, n_basis_funcs, n_neurons) -for k, v in weights.items(): - print(f"{k}: {v.shape}") - -# get the array -weights = weights["convolved counts"] - -# %% -# Multiply the weights by the basis, to get the history filters. - -responses = np.einsum("jki,tk->ijt", weights, basis_kernels) - -print(responses.shape) - -# %% -# Finally, we can visualize the pairwise interactions by plotting -# all the coupling filters. - -doc_plots.plot_coupling(responses, tuning) diff --git a/docs/tutorials/plot_03_grid_cells.py b/docs/tutorials/plot_03_grid_cells.py deleted file mode 100644 index f8532835..00000000 --- a/docs/tutorials/plot_03_grid_cells.py +++ /dev/null @@ -1,252 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -# Fit grid cell - -""" - -import matplotlib.pyplot as plt -import numpy as np -import pynapple as nap -from scipy.ndimage import gaussian_filter - -import nemos as nmo - -# %% -# ## Data Streaming -# -# Here we load the data from OSF. The data is a NWB file. - -io = nmo.fetch.download_dandi_data( - "000582", - "sub-11265/sub-11265_ses-07020602_behavior+ecephys.nwb", -) - -# %% -# ## Pynapple -# -# Let's load the dataset and see what's inside - -dataset = nap.NWBFile(io.read(), lazy_loading=False) - -print(dataset) - - -# %% -# In this case, the data were used in this [publication](https://www.science.org/doi/full/10.1126/science.1125572). -# We thus expect to find neurons tuned to position and head-direction of the animal. -# Let's verify that with pynapple. -# First, extract the spike times and the position of the animal. - - -spikes = dataset["units"] # Get spike timings -position = dataset["SpatialSeriesLED1"] # Get the tracked orientation of the animal - -# %% -# Here we compute quickly the head-direction of the animal from the position of the LEDs. - -diff = dataset["SpatialSeriesLED1"].values - dataset["SpatialSeriesLED2"].values -head_dir = (np.arctan2(*diff.T) + (2 * np.pi)) % (2 * np.pi) -head_dir = nap.Tsd(dataset["SpatialSeriesLED1"].index, head_dir).dropna() - - -# %% -# Let's quickly compute some tuning curves for head-direction and spatial position. - -hd_tuning = nap.compute_1d_tuning_curves( - group=spikes, feature=head_dir, nb_bins=61, minmax=(0, 2 * np.pi) -) - -pos_tuning, binsxy = nap.compute_2d_tuning_curves( - group=spikes, features=position, nb_bins=12 -) - - -# %% -# Let's plot the tuning curves for each neuron. - -fig = plt.figure(figsize=(12, 4)) -gs = plt.GridSpec(2, len(spikes)) -for i in range(len(spikes)): - ax = plt.subplot(gs[0, i], projection="polar") - ax.plot(hd_tuning.loc[:, i]) - - ax = plt.subplot(gs[1, i]) - ax.imshow(gaussian_filter(pos_tuning[i], sigma=1)) -plt.tight_layout() - -# %% -# ## NeMoS -# It's time to use NeMoS. -# Let's try to predict the spikes as a function of position and see if we can generate better tuning curves -# First we start by binning the spike trains in 10 ms bins. - - -bin_size = 0.01 # second -counts = spikes.count(bin_size, ep=position.time_support) - -# %% -# We need to interpolate the position to the same time resolution. -# We can still use pynapple for this. - -position = position.interpolate(counts) - -# %% -# We can define a two-dimensional basis for position by multiplying two one-dimensional bases, -# see [here](../../background/plot_02_ND_basis_function) for more details. - -basis_2d = nmo.basis.RaisedCosineBasisLinear( - n_basis_funcs=10 -) * nmo.basis.RaisedCosineBasisLinear(n_basis_funcs=10) - -# %% -# Let's see what a few basis look like. Here we evaluate it on a 100 x 100 grid. - -X, Y, Z = basis_2d.evaluate_on_grid(100, 100) - -# %% -# We can visualize the basis. - -fig, axs = plt.subplots(2, 5, figsize=(10, 4)) -for k in range(2): - for h in range(5): - axs[k][h].contourf(X, Y, Z[:, :, 50 + 2 * (k + h)], cmap="Blues") - -plt.tight_layout() - -# %% -# Each basis element represent a possible position of the animal in an arena. -# Now we can "evaluate" the basis for each position of the animal - -position_basis = basis_2d(position["x"], position["y"]) - -# %% -# Now try to make sense of what it is -print(position_basis.shape) - -# %% -# The shape is (n_samples, n_basis). This means that for each time point "t", we evaluated the basis at the -# corresponding position. Let's plot 5 time steps. - -fig = plt.figure(figsize=(12, 4)) -gs = plt.GridSpec(2, 5) -xt = np.arange(0, 1000, 200) -cmap = plt.get_cmap("rainbow") -colors = np.linspace(0, 1, len(xt)) -for cnt, i in enumerate(xt): - ax = plt.subplot(gs[0, i // 200]) - ax.imshow(position_basis[i].reshape(10, 10).T, origin="lower") - for spine in ["top", "bottom", "left", "right"]: - ax.spines[spine].set_color(cmap(colors[cnt])) - ax.spines[spine].set_linewidth(3) - plt.title("T " + str(i)) - -ax = plt.subplot(gs[1, 2]) - -ax.plot(position["x"][0:1000], position["y"][0:1000]) -for i in range(len(xt)): - ax.plot(position["x"][xt[i]], position["y"][xt[i]], "o", color=cmap(colors[i])) - -plt.tight_layout() - - -# %% -# Now we can fit the GLM and see what we get. In this case, we use Ridge for regularization. -# Here we will focus on the last neuron (neuron 7) who has a nice grid pattern - -model = nmo.glm.GLM( - regularizer="Ridge", - regularizer_strength=0.001 -) - -# %% -# Let's fit the model - -neuron = 7 - -model.fit(position_basis, counts[:, neuron]) - -# %% -# We can compute the model predicted firing rate. - -rate_pos = model.predict(position_basis) - -# %% -# And compute the tuning curves/ - -model_tuning, binsxy = nap.compute_2d_tuning_curves_continuous( - tsdframe=rate_pos[:, np.newaxis] * rate_pos.rate, features=position, nb_bins=12 -) - -# %% -# Let's compare the tuning curve predicted by the model with that based on the actual spikes. - -smooth_pos_tuning = gaussian_filter(pos_tuning[neuron], sigma=1) -smooth_model = gaussian_filter(model_tuning[0], sigma=1) - -vmin = min(smooth_pos_tuning.min(), smooth_model.min()) -vmax = max(smooth_pos_tuning.max(), smooth_model.max()) - -fig = plt.figure(figsize=(12, 4)) -gs = plt.GridSpec(1, 2) -ax = plt.subplot(gs[0, 0]) -ax.imshow(smooth_pos_tuning, vmin=vmin, vmax=vmax) -ax = plt.subplot(gs[0, 1]) -ax.imshow(smooth_model, vmin=vmin, vmax=vmax) -plt.tight_layout() - -# %% -# The grid shows but the peak firing rate is off, we might have over-regularized. -# We can fix this by tuning the regularization strength by means of cross-validation. -# This can be done through scikit-learn. Let's apply a grid-search over different -# values, and select the regularization by k-fold cross-validation. - -# import the grid-search cross-validation from scikit-learn -from sklearn.model_selection import GridSearchCV - -# define the regularization strength that we want cross-validate -param_grid = dict(regularizer_strength=[1e-6, 1e-5, 1e-3]) - -# pass the model and the grid -cls = GridSearchCV(model, param_grid=param_grid) - -# run the search, the default is a 5-fold cross-validation strategy -cls.fit(position_basis, counts[:, neuron]) - -# %% -# Let's get the best estimator and see what we get. - -best_model = cls.best_estimator_ - -# %% -# Let's predict and compute the tuning curves once again. - -# predict the rate with the selected model -best_rate_pos = best_model.predict(position_basis) - -# compute the 2D tuning -best_model_tuning, binsxy = nap.compute_2d_tuning_curves_continuous( - tsdframe=best_rate_pos[:, np.newaxis] * best_rate_pos.rate, features=position, nb_bins=12 -) - -# %% -# We can now plot the results. - -# plot the resutls -smooth_best_model = gaussian_filter(best_model_tuning[0], sigma=1) - -vmin = min(smooth_pos_tuning.min(), smooth_model.min(), smooth_best_model.min()) -vmax = max(smooth_pos_tuning.max(), smooth_model.max(), smooth_best_model.max()) - -fig, axs = plt.subplots(1, 3, figsize=(12, 4)) -plt.suptitle("Rate predictions\n") -axs[0].set_title("Raw Counts") -axs[0].imshow(smooth_pos_tuning, vmin=vmin, vmax=vmax) -axs[1].set_title(f"Ridge - strength: {model.regularizer_strength}") -axs[1].imshow(smooth_model, vmin=vmin, vmax=vmax) -axs[2].set_title(f"Ridge - strength: {best_model.regularizer_strength}") -axs[2].imshow(smooth_best_model, vmin=vmin, vmax=vmax) -plt.tight_layout() - - - diff --git a/docs/tutorials/plot_04_v1_cells.py b/docs/tutorials/plot_04_v1_cells.py deleted file mode 100644 index ea3da54a..00000000 --- a/docs/tutorials/plot_04_v1_cells.py +++ /dev/null @@ -1,293 +0,0 @@ -# # -*- coding: utf-8 -*- -# -"""# Fit V1 cell - -The data presented in this notebook was collected by [Sonica Saraf](https://www.cns.nyu.edu/~saraf/) from the [Movshon lab](https://www.cns.nyu.edu/labs/movshonlab/) at NYU. - -The notebook focuses on fitting a V1 cell model. - -""" - -import matplotlib.pyplot as plt -import numpy as np -import pynapple as nap - -import nemos as nmo - -# configure plots some -plt.style.use(nmo.styles.plot_style) - - -# utility for filling a time series -def fill_forward(time_series, data, ep=None, out_of_range=np.nan): - """ - Fill a time series forward in time with data. - - Parameters - ---------- - time_series: - The time series to match. - data: Tsd, TsdFrame, or TsdTensor - The time series with data to be extend. - - Returns - ------- - : Tsd, TsdFrame, or TsdTensor - The data time series filled forward. - - """ - assert isinstance(data, (nap.Tsd, nap.TsdFrame, nap.TsdTensor)) - - if ep is None: - ep = time_series.time_support - else: - assert isinstance(ep, nap.IntervalSet) - time_series.restrict(ep) - - data = data.restrict(ep) - starts = ep.start - ends = ep.end - - filled_d = np.full((time_series.t.shape[0], *data.shape[1:]), out_of_range, dtype=data.dtype) - fill_idx = 0 - for start, end in zip(starts, ends): - data_ep = data.get(start, end) - ts_ep = time_series.get(start, end) - idxs = np.searchsorted(data_ep.t, ts_ep.t, side="right") - 1 - filled_d[fill_idx:fill_idx + ts_ep.t.shape[0]][idxs >= 0] = data_ep.d[idxs[idxs>=0]] - fill_idx += ts_ep.t.shape[0] - return type(data)(t=time_series.t, d=filled_d, time_support=ep) - - -# %% -# ## Data Streaming -# - -path = nmo.fetch.fetch_data("m691l1.nwb") - -# %% -# ## Pynapple -# The data have been copied to your local station. -# We are gonna open the NWB file with pynapple - -dataset = nap.load_file(path) - -# %% -# What does it look like? -print(dataset) - -# %% -# Let's extract the data. -epochs = dataset["epochs"] -units = dataset["units"] -stimulus = dataset["whitenoise"] - -# %% -# Stimulus is white noise shown at 40 Hz - -fig, ax = plt.subplots(1, 1, figsize=(12,4)) -ax.imshow(stimulus[0], cmap='Greys_r') -stimulus.shape - -# %% -# There are 73 neurons recorded together in V1. To fit the GLM faster, we will focus on one neuron. -print(units) -# this returns TsGroup with one neuron only -spikes = units[[34]] - -# %% -# How could we predict neuron's response to white noise stimulus? -# -# - we could fit the instantaneous spatial response. that is, just predict -# neuron's response to a given frame of white noise. this will give an x by y -# filter. implicitly assumes that there's no temporal info: only matters what -# we've just seen -# -# - could fit spatiotemporal filter. instead of an x by y that we use -# independently on each frame, fit (x, y, t) over, say 100 msecs. and then -# fit each of these independently (like in head direction example) -# -# - that's a lot of parameters! can simplify by assumping that the response is -# separable: fit a single (x, y) filter and then modulate it over time. this -# wouldn't catch e.g., direction-selectivity because it assumes that phase -# preference is constant over time -# -# - could make use of our knowledge of V1 and try to fit a more complex -# functional form, e.g., a Gabor. -# -# That last one is very non-linear and thus non-convex. we'll do the third one. -# -# in this example, we'll fit the spatial filter outside of the GLM framework, -# using spike-triggered average, and then we'll use the GLM to fit the temporal -# timecourse. -# -# ## Spike-triggered average -# -# Spike-triggered average says: every time our neuron spikes, we store the -# stimulus that was on the screen. for the whole recording, we'll have many of -# these, which we then average to get this STA, which is the "optimal stimulus" -# / spatial filter. -# -# In practice, we do not just the stimulus on screen, but in some window of -# time around it. (it takes some time for info to travel through the eye/LGN to -# V1). Pynapple makes this easy: - - -sta = nap.compute_event_trigger_average(spikes, stimulus, binsize=0.025, - windowsize=(-0.15, 0.0)) -# %% -# -# sta is a `TsdTensor`, which gives us the 2d receptive field at each of the -# time points. - -sta - -# %% -# -# We index into this in a 2d manner: row, column (here we only have 1 column). -sta[1, 0] - -# %% -# we can easily plot this - -fig, axes = plt.subplots(1, len(sta), figsize=(3*len(sta),3)) -for i, t in enumerate(sta.t): - axes[i].imshow(sta[i,0], vmin = np.min(sta), vmax = np.max(sta), - cmap='Greys_r') - axes[i].set_title(str(t)+" s") - - -# %% -# -# that looks pretty reasonable for a V1 simple cell: localized in space, -# orientation, and spatial frequency. that is, looks Gabor-ish -# -# To convert this to the spatial filter we'll use for the GLM, let's take the -# average across the bins that look informative: -.125 to -.05 - -# mkdocs_gallery_thumbnail_number = 3 -receptive_field = np.mean(sta.get(-0.125, -0.05), axis=0)[0] - -fig, ax = plt.subplots(1, 1, figsize=(4,4)) -ax.imshow(receptive_field, cmap='Greys_r') - -# %% -# -# This receptive field gives us the spatial part of the linear response: it -# gives a map of weights that we use for a weighted sum on an image. There are -# multiple ways of performing this operation: - -# element-wise multiplication and sum -print((receptive_field * stimulus[0]).sum()) -# dot product of flattened versions -print(np.dot(receptive_field.flatten(), stimulus[0].flatten())) - -# %% -# -# When performing this operation on multiple stimuli, things become slightly -# more complicated. For loops on the above methods would work, but would be -# slow. Reshaping and using the dot product is one common method, as are -# methods like `np.tensordot`. -# -# We'll use einsum to do this, which is a convenient way of representing many -# different matrix operations: - -filtered_stimulus = np.einsum('t h w, h w -> t', stimulus, receptive_field) - -# %% -# -# This notation says: take these arrays with dimensions `(t,h,w)` and `(h,w)` -# and multiply and sum to get an array of shape `(t,)`. This performs the same -# operations as above. -# -# And this remains a pynapple object, so we can easily visualize it! - -fig, ax = plt.subplots(1, 1, figsize=(12,4)) -ax.plot(filtered_stimulus) - -# %% -# -# But what is this? It's how much each frame in the video should drive our -# neuron, based on the receptive field we fit using the spike-triggered -# average. -# -# This, then, is the spatial component of our input, as described above. -# -# ## Preparing data for NeMoS -# -# We'll now use the GLM to fit the temporal component. To do that, let's get -# this and our spike counts into the proper format for NeMoS: - -# grab spikes from when we were showing our stimulus, and bin at 1 msec -# resolution -bin_size = .001 -counts = spikes[34].restrict(filtered_stimulus.time_support).count(bin_size) -print(counts.rate) -print(filtered_stimulus.rate) - -# %% -# -# Hold on, our stimulus is at a much lower rate than what we want for our rates -# -- in previous tutorials, our input has been at a higher rate than our spikes, -# and so we used `bin_average` to down-sample to the appropriate rate. When the -# input is at a lower rate, we need to think a little more carefully about how -# to up-sample. - -print(counts[:5]) -print(filtered_stimulus[:5]) - -# %% -# -# What was the visual input to the neuron at time 0.005? It was the same input -# as time 0. At time 0.0015? Same thing, up until we pass time 0.025017. Thus, -# we want to "fill forward" the values of our input, and we have pynapple -# convenience function to do so: -filtered_stimulus = fill_forward(counts, filtered_stimulus) -filtered_stimulus - -# %% -# -# We can see that the time points are now aligned, and we've filled forward the -# values the way we'd like. -# -# Now, similar to the [head direction tutorial](../plot_02_head_direction), we'll -# use the log-stretched raised cosine basis to create the predictor for our -# GLM: - -window_size = 100 -basis = nmo.basis.RaisedCosineBasisLog(8, mode="conv", window_size=window_size) - -convolved_input = basis.compute_features(filtered_stimulus) - -# %% -# -# convolved_input has shape (n_time_pts, n_features * n_basis_funcs), because -# n_features is the singleton dimension from filtered_stimulus. -# -# ## Fitting the GLM -# -# Now we're ready to fit the model! Let's do it, same as before: - - -model = nmo.glm.GLM() -model.fit(convolved_input, counts) - -# %% -# -# We have our coefficients for each of our 8 basis functions, let's combine -# them to get the temporal time course of our input: - -time, basis_kernels = basis.evaluate_on_grid(window_size) -time *= bin_size * window_size -temp_weights = np.einsum('b, t b -> t', model.coef_, basis_kernels) -plt.plot(time, temp_weights) -plt.xlabel("time[sec]") -plt.ylabel("amplitude") - -# %% -# -# When taken together, the results of the GLM and the spike-triggered average -# give us the linear component of our LNP model: the separable spatio-temporal -# filter. - - diff --git a/docs/tutorials/plot_05_place_cells.py b/docs/tutorials/plot_05_place_cells.py deleted file mode 100644 index 24ea3f63..00000000 --- a/docs/tutorials/plot_05_place_cells.py +++ /dev/null @@ -1,412 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -# Fit place cell - -The data for this example are from [Grosmark, Andres D., and György Buzsáki. "Diversity in neural firing dynamics supports both rigid and learned hippocampal sequences." Science 351.6280 (2016): 1440-1443](https://www.science.org/doi/full/10.1126/science.aad1935). - -""" - -import matplotlib.pyplot as plt -import numpy as np -import pandas as pd -import pynapple as nap -from scipy.ndimage import gaussian_filter - -import nemos as nmo - -# some helper plotting functions -from nemos import _documentation_utils as doc_plots - -# configure plots some -plt.style.use(nmo.styles.plot_style) - -# %% -# ## Data Streaming -# -# Here we load the data from OSF. The data is a NWB file. - -path = nmo.fetch.fetch_data("Achilles_10252013.nwb") - -# %% -# ## Pynapple -# We are going to open the NWB file with pynapple - -data = nap.load_file(path) - -data - -# %% -# Let's extract the spike times, the position and the theta phase. - -spikes = data["units"] -position = data["position"] -theta = data["theta_phase"] - -# %% -# The NWB file also contains the time at which the animal was traversing the linear track. We can use it to restrict the position and assign it as the `time_support` of position. - -position = position.restrict(data["trials"]) - -# %% -# The recording contains both inhibitory and excitatory neurons. Here we will focus of the excitatory cells. Neurons have already been labelled before. -spikes = spikes.getby_category("cell_type")["pE"] - -# %% -# We can discard the low firing neurons as well. -spikes = spikes.getby_threshold("rate", 0.3) - -# %% -# ## Place fields -# Let's plot some data. We start by making place fields i.e firing rate as a function of position. - -pf = nap.compute_1d_tuning_curves(spikes, position, 50, position.time_support) - -# %% -# Let's do a quick sort of the place fields for display -order = pf.idxmax().sort_values().index.values - -# %% -# Here each row is one neuron - -plt.figure(figsize=(12, 10)) -gs = plt.GridSpec(len(spikes), 1) -for i, n in enumerate(order): - plt.subplot(gs[i, 0]) - plt.fill_between(pf.index.values, np.zeros(len(pf)), pf[n].values) - if i < len(spikes) - 1: - plt.xticks([]) - else: - plt.xlabel("Position (cm)") - plt.yticks([]) - - -# %% -# ## Phase precession -# -# In addition to place modulation, place cells are also modulated by the theta oscillation. The phase at which neurons fire is dependant of the position. This phenomen is called "phase precession" (see [J. O’Keefe, M. L. Recce, "Phase relationship between hippocampal place units and the EEG theta rhythm." Hippocampus 3, 317–330 (1993).](https://doi.org/10.1002/hipo.450030307) -# -# Let's compute the response of the neuron as a function of both theta and position. The phase of theta has already been computed but we have to bring it to the same dimension as the position feature. While the position has been sampled at 40Hz, the theta phase has been computed at 1250Hz. -# Later on during the analysis, we will use a bin size of 5 ms for counting the spikes. Since this corresponds to an intermediate frequency between 40 and 1250 Hz, we will bring all the features to 200Hz already. - -bin_size = 0.005 - -theta = theta.bin_average(bin_size, position.time_support) -theta = (theta + 2 * np.pi) % (2 * np.pi) - -data = nap.TsdFrame( - t=theta.t, - d=np.vstack( - (position.interpolate(theta, ep=position.time_support).values, theta.values) - ).T, - time_support=position.time_support, - columns=["position", "theta"], -) - -print(data) - - - - - -# %% -# `data` is a `TsdFrame` that contains the position and phase. Before calling `compute_2d_tuning_curves` from pynapple to observe the theta phase precession, we will restrict the analysis to the place field of one neuron. -# -# There are a lot of neurons but for this analysis, we will focus on one neuron only. -neuron = 175 - -plt.figure(figsize=(5,3)) -plt.fill_between(pf[neuron].index.values, np.zeros(len(pf)), pf[neuron].values) -plt.xlabel("Position (cm)") -plt.ylabel("Firing rate (Hz)") - -# %% -# This neurons place field is between 0 and 60 cm within the linear track. Here we will use the `threshold` function of pynapple to quickly compute the epochs for which the animal is within the place field : - -within_ep = position.threshold(60.0, method="below").time_support - -# %% -# `within_ep` is an `IntervalSet`. We can now give it to `compute_2d_tuning_curves` along with the spiking activity and the position-phase features. - -tc_pos_theta, xybins = nap.compute_2d_tuning_curves(spikes, data, 20, within_ep) - -# %% -# To show the theta phase precession, we can also display the spike as a function of both position and theta. In this case, we use the function `value_from` from pynapple. - -theta_pos_spikes = spikes[neuron].value_from(data, ep = within_ep) - -# %% -# Now we can plot everything together : - -plt.figure() -gs = plt.GridSpec(2, 2) -plt.subplot(gs[0, 0]) -plt.fill_between(pf[neuron].index.values, np.zeros(len(pf)), pf[neuron].values) -plt.xlabel("Position (cm)") -plt.ylabel("Firing rate (Hz)") - -plt.subplot(gs[1, 0]) -extent = (xybins[0][0], xybins[0][-1], xybins[1][0], xybins[1][-1]) -plt.imshow(gaussian_filter(tc_pos_theta[neuron].T, 1), aspect="auto", origin="lower", extent=extent) -plt.xlabel("Position (cm)") -plt.ylabel("Theta Phase (rad)") - -plt.subplot(gs[1, 1]) -plt.plot(theta_pos_spikes["position"], theta_pos_spikes["theta"], "o", markersize=0.5) -plt.xlabel("Position (cm)") -plt.ylabel("Theta Phase (rad)") - -plt.tight_layout() - -# %% -# ## Speed modulation -# The speed at which the animal traverse the field is not homogeneous. Does it influence the firing rate of hippocampal neurons? We can compute tuning curves for speed as well as average speed across the maze. -# In the next block, we compute the speed of the animal for each epoch (i.e. crossing of the linear track) by doing the difference of two consecutive position multiplied by the sampling rate of the position. - -speed = [] -for s, e in data.time_support.values: # Time support contains the epochs - pos_ep = data["position"].get(s, e) - speed_ep = np.abs(np.diff(pos_ep)) # Absolute difference of two consecutive points - speed_ep = np.pad(speed_ep, [0, 1], mode="edge") # Adding one point at the end to match the size of the position array - speed_ep = speed_ep * data.rate # Converting to cm/s - speed.append(speed_ep) - -speed = nap.Tsd(t=data.t, d=np.hstack(speed), time_support=data.time_support) - -# %% -# Now that we have the speed of the animal, we can compute the tuning curves for speed modulation. Here we call pynapple `compute_1d_tuning_curves`: - -tc_speed = nap.compute_1d_tuning_curves(spikes, speed, 20) - -# %% -# To assess the variabilty in speed when the animal is travering the linear track, we can compute the average speed and estimate the standard deviation. Here we use numpy only and put the results in a pandas `DataFrame`: - -bins = np.linspace(np.min(data["position"]), np.max(data["position"]), 20) - -idx = np.digitize(data["position"].values, bins) - -mean_speed = np.array([np.mean(speed[idx==i]) for i in np.unique(idx)]) -std_speed = np.array([np.std(speed[idx==i]) for i in np.unique(idx)]) - -# %% -# Here we plot the tuning curve of one neuron for speed as well as the average speed as a function of the animal position - -plt.figure(figsize=(8, 3)) -plt.subplot(121) -plt.plot(bins, mean_speed) -plt.fill_between( - bins, - mean_speed - std_speed, - mean_speed + std_speed, - alpha=0.1, -) -plt.xlabel("Position (cm)") -plt.ylabel("Speed (cm/s)") -plt.title("Animal speed") -plt.subplot(122) -plt.fill_between( - tc_speed.index.values, np.zeros(len(tc_speed)), tc_speed[neuron].values -) -plt.xlabel("Speed (cm/s)") -plt.ylabel("Firing rate (Hz)") -plt.title("Neuron {}".format(neuron)) -plt.tight_layout() - -# %% -# This neurons show a strong modulation of firing rate as a function of speed but we can also notice that the animal, on average, accelerates when travering the field. Is the speed tuning we observe a true modulation or spurious correlation caused by traversing the place field at different speed and for different theta phase? We can use NeMoS to model the activity and give the position, the phase and the speed as input variable. -# -# We will use speed, phase and position to model the activity of the neuron. -# All the feature have already been brought to the same dimension thanks to `pynapple`. - -position = data["position"] -theta = data["theta"] -count = spikes[neuron].count(bin_size, data.time_support) - -print(position.shape) -print(theta.shape) -print(speed.shape) -print(count.shape) - -# %% -# ## Basis evaluation -# -# For each feature, we will use a different set of basis : -# -# - position : `nmo.basis.MSplineBasis` -# - theta phase : `nmo.basis.CyclicBSplineBasis` -# - speed : `nmo.basis.MSplineBasis` - -position_basis = nmo.basis.MSplineBasis(n_basis_funcs=10) -phase_basis = nmo.basis.CyclicBSplineBasis(n_basis_funcs=12) -speed_basis = nmo.basis.MSplineBasis(n_basis_funcs=15) - -# %% -# In addition, we will consider position and phase to be a joint variable. In NeMoS, we can combine basis by multiplying them and adding them. In this case the final basis object for our model can be made in one line : - -basis = position_basis * phase_basis + speed_basis - -# %% -# The object basis only tell us how each basis covers the feature space. For each timestep, we need to _evaluate_ what are the features value. For that we can call NeMoS basis: - -X = basis(position, theta, speed) - -# %% -# `X` is our design matrix. For each timestamps, it contains the information about the current position, -# speed and theta phase of the experiment. Notice how passing a pynapple object to the basis -# also returns a `pynapple` object. - -print(X) - -# %% -# ## Model learning -# -# We can now use the Poisson GLM from NeMoS to learn the model. - -glm = nmo.glm.GLM( - solver_kwargs=dict(tol=10**-12), - solver_name="LBFGS" -) - -glm.fit(X, count) - -# %% -# ## Prediction -# -# Let's check first if our model can accurately predict the different tuning curves we displayed above. We can use the `predict` function of NeMoS and then compute new tuning curves - -predicted_rate = glm.predict(X) / bin_size - -glm_pf = nap.compute_1d_tuning_curves_continuous(predicted_rate[:, np.newaxis], position, 50) -glm_pos_theta, xybins = nap.compute_2d_tuning_curves_continuous( - predicted_rate[:, np.newaxis], data, 30, ep=within_ep -) -glm_speed = nap.compute_1d_tuning_curves_continuous(predicted_rate[:, np.newaxis], speed, 30) - -# %% -# Let's display both tuning curves together. -fig = doc_plots.plot_position_phase_speed_tuning( - pf[neuron], - glm_pf[0], - tc_speed[neuron], - glm_speed[0], - tc_pos_theta[neuron], - glm_pos_theta[0], - xybins - ) - -# %% -# ## Model selection -# -# While this model captures nicely the features-rate relationship, it is not necessarily the simplest model. Let's construct several models and evaluate their score to determine the best model. -# -# !!! note -# To shorten this notebook, only a few combinations are tested. Feel free to expand this list. -# - -models = { - "position": position_basis, - "position + speed": position_basis + speed_basis, - "position + phase": position_basis + phase_basis, - "position * phase + speed": position_basis * phase_basis + speed_basis, -} -features = { - "position": (position,), - "position + speed": (position, speed), - "position + phase": (position, theta), - "position * phase + speed": (position, theta, speed), -} - -# %% -# In a loop, we can (1) evaluate the basis, (2), fit the model, (3) compute the score and (4) predict the firing rate. For evaluating the score, we can define a train set of intervals and a test set of intervals. - -train_iset = position.time_support[::2] # Taking every other epoch -test_iset = position.time_support[1::2] - -# %% -# Let's train all the models. -scores = {} -predicted_rates = {} - -for m in models: - print("1. Evaluating basis : ", m) - X = models[m](*features[m]) - - print("2. Fitting model : ", m) - glm.fit( - X.restrict(train_iset), - count.restrict(train_iset), - ) - - print("3. Scoring model : ", m) - scores[m] = glm.score( - X.restrict(test_iset), - count.restrict(test_iset), - score_type="pseudo-r2-McFadden", - ) - - print("4. Predicting rate") - predicted_rates[m] = glm.predict(X.restrict(test_iset)) / bin_size - - -scores = pd.Series(scores) -scores = scores.sort_values() - -# %% -# Let's compute scores for each models. - -plt.figure(figsize=(5, 3)) -plt.barh(np.arange(len(scores)), scores) -plt.yticks(np.arange(len(scores)), scores.index) -plt.xlabel("Pseudo r2") -plt.tight_layout() - - -# %% -# Some models are doing better than others. -# -# !!! warning -# A proper model comparison should be done by scoring models repetitively on various train and test set. Here we are only doing partial models comparison for the sake of conciseness. -# -# Alternatively, we can plot some tuning curves to compare each models visually. - -tuning_curves = {} - -for m in models: - tuning_curves[m] = { - "position": nap.compute_1d_tuning_curves_continuous( - predicted_rates[m][:, np.newaxis], position, 50, ep=test_iset - ), - "speed": nap.compute_1d_tuning_curves_continuous( - predicted_rates[m][:, np.newaxis], speed, 20, ep=test_iset - ), - } - -# recompute tuning from spikes restricting to the test-set -pf = nap.compute_1d_tuning_curves(spikes, position, 50, ep=test_iset) -tc_speed = nap.compute_1d_tuning_curves(spikes, speed, 20, ep=test_iset) - - -fig = plt.figure(figsize=(8, 4)) -outer_grid = fig.add_gridspec(2, 2) -for i, m in enumerate(models): - doc_plots.plot_position_speed_tuning( - outer_grid[i // 2, i % 2], - tuning_curves[m], - pf[neuron], - tc_speed[neuron], - m) - -plt.tight_layout() -plt.show() - -# %% -# ## Conclusion -# -# Various combinations of features can lead to different results. Feel free to explore more. To go beyond this notebook, you can check the following references : -# -# - [Hardcastle, Kiah, et al. "A multiplexed, heterogeneous, and adaptive code for navigation in medial entorhinal cortex." Neuron 94.2 (2017): 375-387](https://www.cell.com/neuron/pdf/S0896-6273(17)30237-4.pdf) -# -# - [McClain, Kathryn, et al. "Position–theta-phase model of hippocampal place cell activity applied to quantification of running speed modulation of firing rate." Proceedings of the National Academy of Sciences 116.52 (2019): 27035-27042](https://www.pnas.org/doi/abs/10.1073/pnas.1912792116) -# -# - [Peyrache, Adrien, Natalie Schieferstein, and Gyorgy Buzsáki. "Transformation of the head-direction signal into a spatial code." Nature communications 8.1 (2017): 1752.](https://www.nature.com/articles/s41467-017-01908-3) -# diff --git a/docs/tutorials/plot_06_calcium_imaging.py b/docs/tutorials/plot_06_calcium_imaging.py deleted file mode 100644 index 54d83666..00000000 --- a/docs/tutorials/plot_06_calcium_imaging.py +++ /dev/null @@ -1,319 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Fit Calcium Imaging -============ - - -For the example dataset, we will be working with a recording of a freely-moving mouse imaged with a Miniscope (1-photon imaging at 30Hz using the genetically encoded calcium indicator GCaMP6f). The area recorded for this experiment is the postsubiculum - a region that is known to contain head-direction cells, or cells that fire when the animal's head is pointing in a specific direction. - -The data were collected by Sofia Skromne Carrasco from the [Peyrache Lab](https://www.peyrachelab.com/). - -""" -import warnings -from warnings import catch_warnings - -import jax -import jax.numpy as jnp -import matplotlib.pyplot as plt -import numpy as np -import pynapple as nap -from sklearn.linear_model import LinearRegression - -import nemos as nmo -from nemos.identifiability_constraints import ( - apply_identifiability_constraints_by_basis_component, -) - -# ignore dtype warnings -nap.nap_config.suppress_conversion_warnings = True -warnings.filterwarnings("ignore", category=UserWarning, message="The feature matrix is not of dtype") - - - -# %% -# configure plots -plt.style.use(nmo.styles.plot_style) - - -# %% -# ## Data Streaming -# -# Here we load the data from OSF. The data is a NWB file. - -path = nmo.fetch.fetch_data("A0670-221213.nwb") - -# %% -# *** -# ## pynapple preprocessing -# -# Now that we have the file, let's load the data. The NWB file contains multiple entries. -data = nap.load_file(path) -print(data) - -# %% -# In the NWB file, the calcium traces are saved the RoiResponseSeries field. Let's save them in a variable called 'transients' and print it. - -transients = data['RoiResponseSeries'] -print(transients) - -# %% -# `transients` is a `TsdFrame`. Each column contains the activity of one neuron. -# -# The mouse was recorded for a 20 minute recording epoch as we can see from the `time_support` property of the `transients` object. - -ep = transients.time_support -print(ep) - - -# %% -# There are a few different ways we can explore the data. First, let's inspect the raw calcium traces for neurons 4 and 35 for the first 250 seconds of the experiment. - -fig, ax = plt.subplots(1, 2, figsize=(12, 4)) -ax[0].plot(transients[:, 4].get(0,250)) -ax[0].set_ylabel("Firing rate (Hz)") -ax[0].set_title("Trace 4") -ax[0].set_xlabel("Time(s)") -ax[1].plot(transients[:, 35].get(0,250)) -ax[1].set_title("Trace 35") -ax[1].set_xlabel("Time(s)") -plt.tight_layout() - -# %% -# You can see that the calcium signals are both nonnegative, and noisy. One (neuron 4) has much higher SNR than the other. We cannot typically resolve individual action potentials, but instead see slow calcium fluctuations that result from an unknown underlying electrical signal (estimating the spikes from calcium traces is known as _deconvolution_ and is beyond the scope of this demo). - -# %% -# We can also plot tuning curves, plotting mean calcium activity as a function of head direction, using the function `compute_1d_tuning_curves_continuous`. -# Here `data['ry']` is a `Tsd` that contains the angular head-direction of the animal between 0 and 2$\pi$. - -tcurves = nap.compute_1d_tuning_curves_continuous(transients, data['ry'], 120) - - - -# %% -# The function returns a pandas DataFrame. Let's plot the tuning curves for neurons 4 and 35. - -fig, ax = plt.subplots(1, 2, figsize=(12, 4)) -ax[0].plot(tcurves.iloc[:, 4]) -ax[0].set_xlabel("Angle (rad)") -ax[0].set_ylabel("Firing rate (Hz)") -ax[0].set_title("Trace 4") -ax[1].plot(tcurves.iloc[:, 35]) -ax[1].set_xlabel("Angle (rad)") -ax[1].set_title("Trace 35") -plt.tight_layout() - -# %% -# As a first processing step, let's bin the calcium traces to a 100ms resolution. - -Y = transients.bin_average(0.1, ep) - -# %% -# We can visualize the downsampled transients for the first 50 seconds of data. -plt.figure() -plt.plot(transients[:,0].get(0, 50), linewidth=5, label="30 Hz") -plt.plot(Y[:,0].get(0, 50), '--', linewidth=2, label="10 Hz") -plt.xlabel("Time (s)") -plt.ylabel("Fluorescence") -plt.legend() -plt.show() - -# %% -# The downsampling did not destroy the fast transient dynamics, so seems fine to use. We can now move on to using NeMoS to fit a model. - -# %% -# ## Basis instantiation -# -# We can define a cyclic-BSpline for capturing the encoding of the heading angle, and a log-spaced raised cosine basis for the coupling filters between neurons. Note that we are not including a self-coupling (spike history) filter, because in practice we have found it results in overfitting. -# -# We can combine the two bases. - -heading_basis = nmo.basis.CyclicBSplineBasis(n_basis_funcs=12) - -# define a basis that expect all the other neurons as predictors, i.e. shape (num_samples, num_neurons - 1) -num_neurons = Y.shape[1] -ws = 10 -coupling_basis = nmo.basis.RaisedCosineBasisLog(3, mode="conv", window_size=ws) - -# %% -# We need to combine the bases. -basis = heading_basis + coupling_basis - - -# %% -# ## Gamma GLM -# -# Until now, we have been modeling spike trains, and have used a Poisson distribution for the observation model. With calcium traces, things are quite different: we no longer have counts but continuous signals, so the Poisson assumption is no longer appropriate. A Gaussian model is also not ideal since the calcium traces are non-negative. To satisfy these constraints, we will use a Gamma distribution from NeMoS with a soft-plus non linearity. -# !!! note "Non-linearity" -# Different option are possible. With a soft-plus we are assuming an "additive" effect of the predictors, while an exponential non-linearity assumes multiplicative effects. Deciding which firing rate model works best is an empirical question. You can fit different configurations to see which one capture best the neural activity. - -model = nmo.glm.GLM( - solver_kwargs=dict(tol=10**-13), - regularizer="Ridge", - regularizer_strength=0.02, - observation_model=nmo.observation_models.GammaObservations(inverse_link_function=jax.nn.softplus) -) - - -# %% -# We select one neuron to fit later, so remove it from the list of predictors - -neu = 4 -selected_neurons = jnp.hstack( - (jnp.arange(0, neu), jnp.arange(neu+1, Y.shape[1])) -) - -print(selected_neurons) - -# %% -# We need to bring the head-direction of the animal to the same size as the transients matrix. -# We can use the function `bin_average` of pynapple. Notice how we pass the parameter `ep` -# that is the `time_support` of the transients. - -head_direction = data['ry'].bin_average(0.1, ep) - -# %% -# Let's check that `head_direction` and `Y` are of the same size. -print(head_direction.shape) -print(Y.shape) - -# %% -# ## Design matrix -# -# We can now create the design matrix by combining the head-direction of the animal and the activity of all other neurons. -X = basis.compute_features(head_direction, Y[:, selected_neurons]) - -# %% -# -# Before we use this design matrix to fit the population, we need to take a brief detour -# into linear algebra. Depending on your design matrix is constructed, it is likely to -# be rank-deficient, in which case it has a null space. Practically, that means that -# there are infinitely many different sets of parameters that predict the same firing -# rate. If you want to interpret your parameters, this is bad! -# -# While this multiplicity of solutions is always a potential issue when fitting models, -# it is particularly relevant when using basis objects in nemos, as many of our basis -# sets completely tile the input space (i.e., summing across all $n$ basis functions -# returns 1 everywhere), which, when combined with the intercept term always present in -# the GLM (i.e., the base firing rate), will give you a rank-deficient matrix. -# -# We thus recommend that you always check the rank of your design matrix and provide -# some tools to drop the linearly-dependent columns, if necessary, which will guarantee -# that your design matrix is full rank and thus that there is one unique solution. -# -# !!! tip "Linear Algebra" -# -# To read more about matrix rank, see -# [Wikipedia](https://en.wikipedia.org/wiki/Rank_(linear_algebra)#Main_definitions). -# Gil Strang's Linear Algebra course, [available for free -# online](https://web.mit.edu/18.06/www/), and [NeuroMatch -# Academy](https://compneuro.neuromatch.io/tutorials/W0D3_LinearAlgebra/student/W0D3_Tutorial2.html) -# are also great resources. -# -# In this case, we are using the CyclicBSpline basis functions, which uniformly tile and -# thus will result in a rank-deficient matrix. Therefore, we will use a utility function -# to drop a column from the matrix and make it full-rank: - -# The number of features is the number of columns plus one (for the intercept) -print(f"Number of features in the rank-deficient design matrix: {X.shape[1] + 1}") -X, _ = apply_identifiability_constraints_by_basis_component(basis, X) -# We have dropped one column -print(f"Number of features in the full-rank design matrix: {X.shape[1] + 1}") - -# %% -# ## Train & test set -# -# Let's create a train epoch and a test epoch to fit and test the models. Since `X` is a pynapple time series, we can create `IntervalSet` objects to restrict them into a train set and test set. - -train_ep = nap.IntervalSet(start=X.time_support.start, end=X.time_support.get_intervals_center().t) -test_ep = X.time_support.set_diff(train_ep) # Removing the train_ep from time_support - -print(train_ep) -print(test_ep) - -# %% -# We can now restrict the `X` and `Y` to create our train set and test set. -Xtrain = X.restrict(train_ep) -Ytrain = Y.restrict(train_ep) - -Xtest = X.restrict(test_ep) -Ytest = Y.restrict(test_ep) - -# %% -# ## Model fitting -# -# It's time to fit the model on the data from the neuron we left out. - -model.fit(Xtrain, Ytrain[:, neu]) - - -# %% -# ## Model comparison - -# %% -# We can compare this to scikit-learn [linear regression](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html). - -mdl = LinearRegression() -valid = ~jnp.isnan(Xtrain.d.sum(axis=1)) # Scikit learn does not like nans. -mdl.fit(Xtrain[valid], Ytrain[valid, neu]) - - -# %% -# We now have 2 models we can compare. Let's predict the activity of the neuron during the test epoch. - -yp = model.predict(Xtest) -ylreg = mdl.predict(Xtest) # Notice that this is not a pynapple object. - -# %% -# Unfortunately scikit-learn has not adopted pynapple yet. Let's convert `ylreg` to a pynapple object to make our life easier. - -ylreg = nap.Tsd(t=yp.t, d=ylreg, time_support = yp.time_support) - - -# %% -# Let's plot the predicted activity for the first 60 seconds of data. - -# mkdocs_gallery_thumbnail_number = 3 - -ep_to_plot = nap.IntervalSet(test_ep.start+20, test_ep.start+80) - -plt.figure() -plt.plot(Ytest[:,neu].restrict(ep_to_plot), "r", label="true", linewidth=2) -plt.plot(yp.restrict(ep_to_plot), "k", label="gamma-nemos", alpha=1) -plt.plot(ylreg.restrict(ep_to_plot), "g", label="linreg-sklearn", alpha=0.5) -plt.legend(loc='best') -plt.xlabel("Time (s)") -plt.ylabel("Fluorescence") -plt.show() - -# %% -# While there is some variability in the fit for both models, one advantage of the gamma distribution is clear: the nonnegativity constraint is followed with the data. -# This is required for using GLMs to predict the firing rate, which must be positive, in response to simulated inputs. See Peyrache et al. 2018[$^{[1]}$](#ref-1) for an example of simulating activity with a GLM. -# -# Another way to compare models is to compute tuning curves. Here we use the function `compute_1d_tuning_curves_continuous` from pynapple. - -real_tcurves = nap.compute_1d_tuning_curves_continuous(transients, data['ry'], 120, ep=test_ep) -gamma_tcurves = nap.compute_1d_tuning_curves_continuous(yp, data['ry'], 120, ep=test_ep) -linreg_tcurves = nap.compute_1d_tuning_curves_continuous(ylreg, data['ry'], 120, ep=test_ep) - -# %% -# Let's plot them. - -plt.figure() -plt.plot(real_tcurves[neu], "r", label="true", linewidth=2) -plt.plot(gamma_tcurves, "k", label="gamma-nemos", alpha=1) -plt.plot(linreg_tcurves, "g", label="linreg-sklearn", alpha=0.5) -plt.legend(loc='best') -plt.ylabel("Fluorescence") -plt.xlabel("Head-direction (rad)") -plt.show() - -#%% -# !!! note "Gamma-GLM for Calcium Imaging Analysis" -# Using Gamma-GLMs for fitting calcium imaging data is still in early stages, and hasn't been through -# the levels of review and validation that they have for fitting spike data. Users should consider -# this a relatively unexplored territory, and we hope that we hope that NeMoS will help researchers -# explore this new space of models. -# -# ## References -# -# [1] Peyrache, A., Schieferstein, N. & Buzsáki, G. Transformation of the head-direction signal into a spatial code. Nat Commun 8, 1752 (2017). https://doi.org/10.1038/s41467-017-01908-3 From 384151ebd48577fa5fcc2c93de434d720965f644 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 14 Nov 2024 20:30:40 -0500 Subject: [PATCH 021/107] fixed math --- docs/background/plot_00_conceptual_intro.md | 6 ++++-- docs/quickstart.md | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/background/plot_00_conceptual_intro.md b/docs/background/plot_00_conceptual_intro.md index 07894f19..57763dcc 100644 --- a/docs/background/plot_00_conceptual_intro.md +++ b/docs/background/plot_00_conceptual_intro.md @@ -83,7 +83,7 @@ The model receives some input and then: Let's step through each of those in turn. Our input feature(s) are first passed through a linear transformation, which -rescales and shifts the input: $\bm{WX}+\bm{c}$. In the one-dimensional case, as +rescales and shifts the input: $ \boldsymbol{W X} + \boldsymbol{c} $. In the one-dimensional case, as in this example, this is equivalent to scaling it by a constant and adding an intercept. @@ -102,7 +102,9 @@ This means that, in the 1d case, we have two knobs to transform the input: we can make it bigger or smaller, or we can shift it up or down. That is, we compute: -$$L(x(t)) = w x(t) + c \tag{1}$$ +$$ +L(x(t)) = w x(t) + c \tag{1} +$$ for some value of $w$ and $c$. Let's visualize some possible transformations that our model can make with three cartoon neurons: diff --git a/docs/quickstart.md b/docs/quickstart.md index aa234489..94dd6a75 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -151,7 +151,7 @@ The `basis` module includes objects that perform two types of transformations on ### **Non-linear Mapping**
- +
Figure 1: Basis as non-linear mappings. The figure demonstrate the use of basis functions to create complex non-linear features for a GLM.
@@ -188,7 +188,7 @@ shape `(n_samples, n_basis_funcs)`, where each column represents a feature gener ### **Convolution**
- GLM Population Scheme + GLM Population Scheme
Figure 2: Basis as a bank of convolutional filters. The figure shows a population GLM for functional connectivity analysis, a classical use-case for basis functions in convolutional mode.
@@ -381,7 +381,7 @@ Finally, let's compare the tuning curves ``` - + ## **Compatibility with `scikit-learn`** From 7e9401b7ea101564aa445f3b4a0fb19a71e01679 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 14 Nov 2024 20:50:55 -0500 Subject: [PATCH 022/107] fixed background --- docs/background/README.md | 5 +- docs/background/plot_01_1D_basis_function.md | 19 ++--- docs/background/plot_02_ND_basis_function.md | 75 +++++++++++++------- docs/background/plot_03_1D_convolution.md | 20 +++--- 4 files changed, 71 insertions(+), 48 deletions(-) diff --git a/docs/background/README.md b/docs/background/README.md index 743adf73..0aa1b8a3 100644 --- a/docs/background/README.md +++ b/docs/background/README.md @@ -14,4 +14,7 @@ pip install nemos[examples] ## Index -[Generalized Linear Models: An Introduction](#glm_intro_background) \ No newline at end of file +- [**Generalized Linear Models: An Introduction**](#glm_intro_background) +- [**Simple Basis Function**](#simple_basis_function) +- [**Composing Basis Function**](#composing_basis_function) +- [**Convolution**](#convolution_background) \ No newline at end of file diff --git a/docs/background/plot_01_1D_basis_function.md b/docs/background/plot_01_1D_basis_function.md index f4063f2d..ee9472d5 100644 --- a/docs/background/plot_01_1D_basis_function.md +++ b/docs/background/plot_01_1D_basis_function.md @@ -15,8 +15,8 @@ kernelspec: %matplotlib inline ``` - -# One-Dimensional Basis +(simple_basis_function)= +# Simple Basis Function ## Defining a 1D Basis Object @@ -138,13 +138,14 @@ axs[2].set_ylabel("basis", fontsize=12) plt.tight_layout() ``` -!!! note "NaN-Padding" - Convolution is performed in "valid" mode, and then NaN-padded. The default behavior - is padding left, which makes the output feature causal. - This is why the first half of the `conv_feature` is full of NaNs and appears as white. - If you want to learn more about convolutions, as well as how and when to change defaults - check out the tutorial on [1D convolutions](../plot_03_1D_convolution). - +:::{admonition} NaN-Padding +:class: note +Convolution is performed in "valid" mode, and then NaN-padded. The default behavior +is padding left, which makes the output feature causal. +This is why the first half of the `conv_feature` is full of NaNs and appears as white. +If you want to learn more about convolutions, as well as how and when to change defaults +check out the tutorial on [1D convolutions](../plot_03_1D_convolution). +::: +++ diff --git a/docs/background/plot_02_ND_basis_function.md b/docs/background/plot_02_ND_basis_function.md index e0e47776..84e2c290 100644 --- a/docs/background/plot_02_ND_basis_function.md +++ b/docs/background/plot_02_ND_basis_function.md @@ -15,8 +15,8 @@ kernelspec: %matplotlib inline ``` - -# Multidimensional Basis +(composing_basis_function)= +# Composing Basis Functions ## Background @@ -33,28 +33,47 @@ Consider we have two inputs $\mathbf{x} \in \mathbb{R}^N,\; \mathbf{y}\in \mathb Let's say we've defined two basis functions for these inputs: - $ [ a_0 (\mathbf{x}), ..., a_{k-1} (\mathbf{x}) ] $ for $\mathbf{x}$ -- $[b_0 (\mathbf{y}), ..., b_{h-1} (\mathbf{y}) ]$ for $\mathbf{y}$. +- $ [b_0 (\mathbf{y}), ..., b_{h-1} (\mathbf{y}) ] $ for $\mathbf{y}$. These basis functions can be combined in the following ways: 1. **Addition:** If we assume that there is no interaction between the stimuli, the response function can be adequately described by the sum of the individual components. The function is defined as: + + $$ + f(\mathbf{x}, \mathbf{y}) \approx \sum_{i=0}^{k-1} \alpha_{i} \, a_i (\mathbf{x}) + \sum_{j=0}^{h-1} \beta_j b_j(\mathbf{y}). $$ - f(\mathbf{x}, \mathbf{y}) \\approx \sum_{i=0}^{k-1} \\alpha_{i} \, a_i (\mathbf{x}) + \sum_{j=0}^{h-1} \\beta_j b_j(\mathbf{y}). + + The resulting additive basis simply consists of the concatenation of the two basis sets: + + $$ + [A_0 (\mathbf{x}, \mathbf{y}), ..., A_{k+h-1} (\mathbf{x}, \mathbf{y})], $$ - The resulting additive basis simply consists of the concatenation of the two basis sets: $$[A_0 (\mathbf{x}, \mathbf{y}), ..., A_{k+h-1} (\mathbf{x}, \mathbf{y})],$$ where + + where + $$ - A_j(\mathbf{x}, \mathbf{y}) = \\begin{cases} a_j(\mathbf{x}) & \\text{if }\; j \leq k-1 \\\\\ b_{j-k+1}(\mathbf{y}) & \\text{otherwise.} \end{cases} + A_j(\mathbf{x}, \mathbf{y}) = \begin{cases} a_j(\mathbf{x}) &\text{if }\; j \leq k-1 \\ + b_{j-k+1}(\mathbf{y}) &\text{otherwise.} \end{cases} $$ + Note that we have a total of $k+h$ basis elements, and that each element is constant in one of the axis. 2. **Multiplication:** If we expect the response function to capture arbitrary interactions between the inputs, we can approximate it as the external product of the two bases: + + $$ + f(\mathbf{x}, \mathbf{y}) \approx \sum_{i=0}^{k-1}\sum_{j=0}^{h-1} \alpha_{ij} \, a_i (\mathbf{x}) b_j(\mathbf{y}). + $$ + + In this case, the resulting basis consists of the $h \cdot k$ products of the individual bases: + $$ - f(\mathbf{x}, \mathbf{y}) \\approx \sum_{i=0}^{k-1}\sum_{j=0}^{h-1} \\alpha_{ij} \, a_i (\mathbf{x}) b_j(\mathbf{y}). + [A_0(\mathbf{x}, \mathbf{y}),..., A_{k \cdot h-1}(\mathbf{x}, \mathbf{y})], $$ - In this case, the resulting basis consists of the $h \cdot k$ products of the individual bases: $$[A_0(\mathbf{x}, \mathbf{y}),..., A_{k \cdot h-1}(\mathbf{x}, \mathbf{y})],$$ + where, + $$ - A_{i \cdot h + j}(\mathbf{x}, \mathbf{y}) = a_i(\mathbf{x})b_{j}(\mathbf{y}), \; \\text{for} \; i=0,\dots, k-1 \; \\text{ and } \; j=0,\dots,h-1. + A_{i \cdot h + j}(\mathbf{x}, \mathbf{y}) = a_i(\mathbf{x})b_{j}(\mathbf{y}), \; \text{for} \; i=0,\dots, k-1 \; \text{ and } \; j=0,\dots,h-1. $$ In the subsequent sections, we will: @@ -72,9 +91,11 @@ In this scenario, the stimuli are the 2D coordinates (x, y) that represent the a ### Additive Basis Object One way to model the response to our 2D stimuli is to hypothesize that it decomposes into two factors: one due to the x-coordinate and another due to the y-coordinate. We can express this relationship as: + $$ -f(x,y) \\approx \sum_i \alpha_i \cdot a_i(x) + \sum_j \beta_j \cdot b_j(y). +f(x,y) \approx \sum_i \alpha_i \cdot a_i(x) + \sum_j \beta_j \cdot b_j(y). $$ + Here, we simply add two basis objects, `a_basis` and `b_basis`, together to define the additive basis. @@ -178,7 +199,7 @@ If the aim is to capture interactions between the coordinates, the response func product of two 1D basis functions. The approximation of the response function in this scenario would be: $$ -f(x, y) \\approx \sum_{ij} \\alpha_{ij} \, a_i (x) b_j(y). +f(x, y) \approx \sum_{ij} \alpha_{ij} \, a_i (x) b_j(y). $$ In this model, we define the 2D basis function as the product of two 1D basis objects. @@ -248,12 +269,12 @@ axs[2, 1].set_xlabel('y-coord') plt.tight_layout() ``` -!!! info - Basis objects of different types can be combined through multiplication or addition. - This feature is particularly useful when one of the axes represents a periodic variable and another is non-periodic. - A practical example would be characterizing the responses to position - in a linear maze and the LFP phase angle. - +:::{info} +Basis objects of different types can be combined through multiplication or addition. +This feature is particularly useful when one of the axes represents a periodic variable and another is non-periodic. +A practical example would be characterizing the responses to position +in a linear maze and the LFP phase angle. +::: +++ @@ -263,12 +284,12 @@ Sometimes it may be useful to model even higher dimensional interactions, for ex an animal and its spatial position. In order to model an N-dimensional response function, you can combine N 1D basis objects using additions and multiplications. -!!! warning - If you multiply basis together, the dimension of the evaluated basis function - will increase exponentially with the number of dimensions potentially causing memory errors. - For example, evaluating a product of $N$ 1D bases with $T$ samples and $K$ basis element, - will output a $K^N \times T$ matrix. - +:::{warning} +If you multiply basis together, the dimension of the evaluated basis function +will increase exponentially with the number of dimensions potentially causing memory errors. +For example, evaluating a product of $N$ 1D bases with $T$ samples and $K$ basis element, +will output a $K^N \times T$ matrix. +::: ```{code-cell} ipython3 T = 10 @@ -316,10 +337,10 @@ plt.show() print(f"Sparsity check: {(Z == 0).sum() / Z.size * 100: .2f}% of the evaluated basis is null.") ``` -!!! info - The evaluated basis is going to be **sparse** if the basis elements support do not cover the - full domain of the basis. - +:::{info} +The evaluated basis is going to be **sparse** if the basis elements support do not cover the +full domain of the basis. +::: +++ diff --git a/docs/background/plot_03_1D_convolution.md b/docs/background/plot_03_1D_convolution.md index 5d45b2a7..84e2ff32 100644 --- a/docs/background/plot_03_1D_convolution.md +++ b/docs/background/plot_03_1D_convolution.md @@ -15,10 +15,8 @@ kernelspec: %matplotlib inline ``` - -One-dimensional convolutions - -+++ +(convolution_background)= +# Convolution ## Generate synthetic data Generate some simulated spike counts. @@ -48,13 +46,13 @@ spk[-4] = 1 ## Convolution in `"valid"` mode Generate and plot a filter, then execute a convolution in "valid" mode for all trials and neurons. -!!! info - The `"valid"` mode of convolution only calculates the product when the two input vectors overlap completely, - avoiding border artifacts. The outcome of such a convolution will - be an array of `max(M,N) - min(M,N) + 1` elements in length, where `M` and `N` represent the number - of elements in the arrays being convolved. For more detailed information on this, - see [jax.numpy.convolve](https://jax.readthedocs.io/en/latest/_autosummary/jax.numpy.convolve.html). - +:::{info} +The `"valid"` mode of convolution only calculates the product when the two input vectors overlap completely, +avoiding border artifacts. The outcome of such a convolution will +be an array of `max(M,N) - min(M,N) + 1` elements in length, where `M` and `N` represent the number +of elements in the arrays being convolved. For more detailed information on this, +see [jax.numpy.convolve](https://jax.readthedocs.io/en/latest/_autosummary/jax.numpy.convolve.html). +::: ```{code-cell} ipython3 # create three filters From f3049fa7afa8a489fb3cc72dff2ba57f231cd91d Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 14 Nov 2024 21:07:58 -0500 Subject: [PATCH 023/107] edis to background --- docs/assets/stylesheets/custom.css | 12 ++++++++++++ docs/background/README.md | 13 ++++++++----- docs/conf.py | 2 +- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/docs/assets/stylesheets/custom.css b/docs/assets/stylesheets/custom.css index ec3c1f7f..2d83a40d 100644 --- a/docs/assets/stylesheets/custom.css +++ b/docs/assets/stylesheets/custom.css @@ -81,3 +81,15 @@ html[data-theme=light]{ .sd-col { margin-bottom: 20px; /* Adjust this value as needed for desired spacing */ } + +/* Style level-1 ToC entries */ +.toctree-l1 { + font-weight: bold; +} + +/* Keep level-2 and deeper ToC entries unbolded */ +.toctree-l2, +.toctree-l3, +.toctree-l4 { + font-weight: normal; +} diff --git a/docs/background/README.md b/docs/background/README.md index 0aa1b8a3..a46996d1 100644 --- a/docs/background/README.md +++ b/docs/background/README.md @@ -12,9 +12,12 @@ pip install nemos[examples] ::: -## Index +```{toctree} +:maxdepth: 2 +:caption: Contents -- [**Generalized Linear Models: An Introduction**](#glm_intro_background) -- [**Simple Basis Function**](#simple_basis_function) -- [**Composing Basis Function**](#composing_basis_function) -- [**Convolution**](#convolution_background) \ No newline at end of file +plot_00_conceptual_intro.md +plot_01_1D_basis_function.md +plot_02_ND_basis_function.md +plot_03_1D_convolution.md +``` \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index b7f4b9a0..5ac7bae3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -138,7 +138,7 @@ ], "show_prev_next": True, "header_links_before_dropdown": 5, - "navigation_depth": 2, + "navigation_depth": 3, } html_context = { From 2c608923d4a29b60a54f0b12a862d20a0036ce11 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 15 Nov 2024 11:39:45 -0500 Subject: [PATCH 024/107] reformat files --- .gitignore | 10 ++++++++ docs/api_guide.rst | 18 +++++++++++++ docs/background/README.md | 6 +++-- docs/background/plot_01_1D_basis_function.md | 22 ++++++++-------- docs/background/plot_02_ND_basis_function.md | 1 + docs/background/plot_03_1D_convolution.md | 11 ++++---- docs/conf.py | 10 ++------ docs/how_to_guide/README.md | 27 +++++++++++++++----- pyproject.toml | 1 + src/nemos/convolve.py | 17 ++++++------ src/nemos/simulation.py | 2 +- 11 files changed, 84 insertions(+), 41 deletions(-) diff --git a/.gitignore b/.gitignore index 970ea314..f0d8fd49 100644 --- a/.gitignore +++ b/.gitignore @@ -143,3 +143,13 @@ docs/generated/ # nwb cahce nwb-cache/ + +# scripting folder +_scripts/ + +# env variable for nwbs +docs/data/ + +# rst generated files +docs/stubs + diff --git a/docs/api_guide.rst b/docs/api_guide.rst index 34a7e364..f727f1a8 100644 --- a/docs/api_guide.rst +++ b/docs/api_guide.rst @@ -17,6 +17,7 @@ Classes for creating Generalized Linear Models (GLMs) for both single neurons an GLM PopulationGLM +.. _nemos_basis: The ``nemos.basis`` module -------------------------- Provides basis function classes to construct and transform features for model inputs. @@ -28,6 +29,7 @@ Provides basis function classes to construct and transform features for model in :recursive: :nosignatures: + Basis BSplineBasis CyclicBSplineBasis MSplineBasis @@ -83,6 +85,22 @@ Utility functions for simulating spiking activity in recurrently connected neura difference_of_gammas regress_filter + +The ``nemos.convolve`` module +----------------------------- +Utility functions for running convolution over the sample axis. + +.. currentmodule:: nemos.convolve + +.. autosummary:: + :toctree: generated/regularizer + :recursive: + :nosignatures: + + create_convolutional_predictor + tensor_convolve + + The ``nemos.identifiability_constraints`` module ------------------------------------------------ Functions to apply identifiability constraints to rank-deficient feature matrices, ensuring the uniqueness of model diff --git a/docs/background/README.md b/docs/background/README.md index a46996d1..2fdf2c7d 100644 --- a/docs/background/README.md +++ b/docs/background/README.md @@ -2,8 +2,10 @@ These notes aim to provide the essential background knowledge needed to understand the models and data processing techniques implemented in NeMoS. -:::{admonition} Additional requirements -:class: attention +:::{dropdown} Additional requirements +:color: warning +:icon: alert + To run the tutorials, you may need to install some additional packages used for plotting and data fetching. You can install all of the required packages with the following command: ``` diff --git a/docs/background/plot_01_1D_basis_function.md b/docs/background/plot_01_1D_basis_function.md index ee9472d5..d8801fde 100644 --- a/docs/background/plot_01_1D_basis_function.md +++ b/docs/background/plot_01_1D_basis_function.md @@ -20,7 +20,7 @@ kernelspec: ## Defining a 1D Basis Object -We'll start by defining a 1D basis function object of the type `MSplineBasis`. +We'll start by defining a 1D basis function object of the type [`MSplineBasis`](nemos.basis.MSplineBasis). The hyperparameters required to initialize this class are: - The number of basis functions, which should be a positive integer. @@ -43,8 +43,8 @@ bspline = nmo.basis.BSplineBasis(n_basis_funcs=n_basis, order=order) ## Evaluating a Basis -The `Basis` object is callable, and can be evaluated as a function. By default, the support of the basis -is defined by the samples that we input to the `__call__` method, and covers from the smallest to the largest value. +The [`Basis`](nemos.basis.Basis) object is callable, and can be evaluated as a function. By default, the support of the basis +is defined by the samples that we input to the [`__call__`](nemos.basis.Basis.__call__) method, and covers from the smallest to the largest value. ```{code-cell} ipython3 @@ -93,11 +93,11 @@ plt.tight_layout() ``` ## Basis `mode` -In constructing features, `Basis` objects can be used in two modalities: `"eval"` for evaluate or `"conv"` -for convolve. These two modalities change the behavior of the `construct_features` method of `Basis`, in particular, +In constructing features, [`Basis`](nemos.basis.basis) objects can be used in two modalities: `"eval"` for evaluate or `"conv"` +for convolve. These two modalities change the behavior of the [`compute_features`](nemos.basis.Basis.compute_features) method of [`Basis`](nemos.basis.Basis), in particular, -- If a basis is in mode `"eval"`, then `construct_features` simply returns the evaluated basis. -- If a basis is in mode `"conv"`, then `construct_features` will convolve the input with a kernel of basis +- If a basis is in mode `"eval"`, then [`compute_features`](nemos.basis.Basis.compute_features) simply returns the evaluated basis. +- If a basis is in mode `"conv"`, then [`compute_features`](nemos.basis.Basis.compute_features) will convolve the input with a kernel of basis with `window_size` specified by the user. Let's see how this two modalities operate. @@ -144,7 +144,7 @@ Convolution is performed in "valid" mode, and then NaN-padded. The default behav is padding left, which makes the output feature causal. This is why the first half of the `conv_feature` is full of NaNs and appears as white. If you want to learn more about convolutions, as well as how and when to change defaults -check out the tutorial on [1D convolutions](../plot_03_1D_convolution). +check out the tutorial on [1D convolutions](plot_03_1D_convolution). ::: +++ @@ -152,11 +152,11 @@ check out the tutorial on [1D convolutions](../plot_03_1D_convolution). Plotting the Basis Function Elements: -------------------------------------- We suggest visualizing the basis post-instantiation by evaluating each element on a set of equi-spaced sample points -and then plotting the result. The method `Basis.evaluate_on_grid` is designed for this, as it generates and returns +and then plotting the result. The method [`Basis.evaluate_on_grid`](nemos.basis.Basis.evaluate_on_grid) is designed for this, as it generates and returns the equi-spaced samples along with the evaluated basis functions. The benefits of using Basis.evaluate_on_grid become particularly evident when working with multidimensional basis functions. You can find more details and visual background in the -[2D basis elements plotting section](../plot_02_ND_basis_function/#plotting-2d-additive-basis-elements). +[2D basis elements plotting section](plotting-2d-additive-basis-elements). ```{code-cell} ipython3 @@ -174,7 +174,7 @@ plt.show() Other Basis Types ----------------- Each basis type may necessitate specific hyperparameters for instantiation. For a comprehensive description, -please refer to the [API Guide](../../../reference/nemos/basis). After instantiation, all classes +please refer to the [API Guide](nemos_basis). After instantiation, all classes share the same syntax for basis evaluation. The following is an example of how to instantiate and evaluate a log-spaced cosine raised function basis. diff --git a/docs/background/plot_02_ND_basis_function.md b/docs/background/plot_02_ND_basis_function.md index 84e2c290..017d4ce5 100644 --- a/docs/background/plot_02_ND_basis_function.md +++ b/docs/background/plot_02_ND_basis_function.md @@ -133,6 +133,7 @@ print(f"Sum of two 1D splines with {eval_basis.shape[1]} " f"\t- a_basis had {a_basis.n_basis_funcs} elements\n\t- b_basis had {b_basis.n_basis_funcs} elements.") ``` +(plotting-2d-additive-basis-elements)= #### Plotting 2D Additive Basis Elements Let's select and plot a basis element from each of the basis we added. diff --git a/docs/background/plot_03_1D_convolution.md b/docs/background/plot_03_1D_convolution.md index 84e2ff32..fe25a6d6 100644 --- a/docs/background/plot_03_1D_convolution.md +++ b/docs/background/plot_03_1D_convolution.md @@ -45,6 +45,7 @@ spk[-4] = 1 ## Convolution in `"valid"` mode Generate and plot a filter, then execute a convolution in "valid" mode for all trials and neurons. +In nemos, you can use the [`tensor_convolve`](nemos.convolve.tensor_convolve) function for this. :::{info} The `"valid"` mode of convolution only calculates the product when the two input vectors overlap completely, @@ -61,7 +62,7 @@ _, w = basis_obj.evaluate_on_grid(ws) plt.plot(w) -spk_conv = nmo.convolve.reshape_convolve(spk, w) +spk_conv = nmo.convolve.tensor_convolve(spk, w) # valid convolution should be of shape n_samples - ws + 1 print(f"Shape of the convolution output: {spk_conv.shape}") @@ -80,7 +81,7 @@ before a movement is initiated (here the event is. "movement onset"). Finally, if one wants to capture both causal and anti-causal effects one should use the acausal filters. -Below we provide a function that runs the convolution in "valid" mode and pads the convolution output +Below we provide the function [`create_convolutional_predictor`](nemos.convolve.create_convolutional_predictor) that runs the convolution in "valid" mode and pads the convolution output for the different filter types. @@ -137,10 +138,10 @@ plt.ylabel('acausal') plt.tight_layout() ``` -## Convolve using `Basis.compute_features` -All the parameters of `create_convolutional_predictor` can be passed to a `Basis` directly +## Convolve using [`Basis.compute_features`](nemos.basis.Basis.compute_features) +All the parameters of [`create_convolutional_predictor`](nemos.convolve.create_convolutional_predictor) can be passed to a [`Basis`](nemos.basis.Basis) directly at initialization. Note that you must set `mode == "conv"` to actually perform convolution -with `Basis.compute_features`. Let's see how we can get the same results through `Basis`. +with [`Basis.compute_features`](nemos.basis.Basis.compute_features). Let's see how we can get the same results through [`Basis`](nemos.basis.Basis). ```{code-cell} ipython3 diff --git a/docs/conf.py b/docs/conf.py index 5ac7bae3..26aa9f06 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -54,23 +54,17 @@ 'sphinx_contributors', 'sphinx_code_tabs', 'sphinx.ext.mathjax', - 'sphinx_autodoc_typehints' + 'sphinx_autodoc_typehints', + 'sphinx_togglebutton', ] myst_enable_extensions = [ "amsmath", "attrs_inline", "colon_fence", - # "deflist", "dollarmath", - # "fieldlist", "html_admonition", "html_image", - # "replacements", - # "smartquotes", - # "strikethrough", - # "substitution", - # "tasklist", ] templates_path = ['_templates'] diff --git a/docs/how_to_guide/README.md b/docs/how_to_guide/README.md index fa4b58fb..1b919c70 100644 --- a/docs/how_to_guide/README.md +++ b/docs/how_to_guide/README.md @@ -3,9 +3,24 @@ Familiarize with NeMoS modules and learn how to take advantage of the `pynapple` and `scikit-learn` compatibility. -??? attention "Additional requirements" - To run the tutorials, you may need to install some additional packages used for plotting and data fetching. - You can install all of the required packages with the following command: - ``` - pip install nemos[examples] - ``` +:::{dropdown} Additional requirements +:color: warning +:icon: alert +To run the tutorials, you may need to install some additional packages used for plotting and data fetching. +You can install all of the required packages with the following command: +``` +pip install nemos[examples] +``` +::: + + +```{toctree} +:maxdepth: 2 +:caption: Contents + +plot_02_glm_demo.md +plot_04_population_glm.md +plot_05_batch_glm.md +plot_06_sklearn_pipeline_cv_demo.md +plot_03_glm_pytree.md +``` \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 770224ab..1e01d4ee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,6 +65,7 @@ docs = [ "sphinx-design", "sphinx-issues", "sphinxcontrib-apidoc", + "sphinx-togglebutton", "myst-parser", "myst-nb", "dandi", diff --git a/src/nemos/convolve.py b/src/nemos/convolve.py index 6a6294c3..faddac39 100644 --- a/src/nemos/convolve.py +++ b/src/nemos/convolve.py @@ -21,7 +21,7 @@ @jax.jit -def reshape_convolve(array: NDArray, eval_basis: NDArray): +def tensor_convolve(array: NDArray, eval_basis: NDArray): """ Apply a convolution on the given array with the evaluation basis and reshapes the result. @@ -32,22 +32,23 @@ def reshape_convolve(array: NDArray, eval_basis: NDArray): Parameters ---------- array : - The input array to convolve. It is expected to be at least 1D. + The input array to convolve. It is expected to be at least 1D. The first axis is expeted to be + the sample axis, i.e. the shape of array is ``(num_samples, ...)``. eval_basis : The evaluation basis array for convolution. It should be 2D, where the first dimension - represents the window size for convolution. + represents the window size for convolution. Shape ``(window_size, n_basis_funcs)``. Returns ------- : The convolved array, reshaped to maintain the original dimensions except for the first one, - which is adjusted based on the window size of `eval_basis`. + which is adjusted based on the window size of ``eval_basis``. Notes ----- - The convolution implemented here is in mode `"valid"`. This implies that the time axis shrinks - `num_samples - window_size + 1`, where num_samples is the first size of the first axis of `array` - and `window_size` is the size of the first axis in `eval_basis`. + The convolution implemented here is in mode ``"valid"``. This implies that the time axis shrinks + ``num_samples - window_size + 1``, where num_samples is the first size of the first axis of ``array`` + and ``window_size`` is the size of the first axis in ``eval_basis``. """ # flatten over other dims & apply vectorized conv conv = _CORR_VEC(array.reshape(array.shape[0], -1), eval_basis) @@ -95,7 +96,7 @@ def _shift_time_axis_and_convolve(array: NDArray, eval_basis: NDArray, axis: int # convolve if array.ndim > 1: - conv = reshape_convolve(array, eval_basis) + conv = tensor_convolve(array, eval_basis) else: conv = _CORR_VEC_BASIS(array, eval_basis) diff --git a/src/nemos/simulation.py b/src/nemos/simulation.py index c62d5c8c..3f0ddd25 100644 --- a/src/nemos/simulation.py +++ b/src/nemos/simulation.py @@ -381,7 +381,7 @@ def scan_fn( # 1. The first dimension is time, and 1 is by construction since we are simulating 1 # sample # 2. Flatten to shape (n_neuron * n_basis_coupling, ) - conv_act = convolve.reshape_convolve(activity, coupling_basis_matrix).reshape( + conv_act = convolve.tensor_convolve(activity, coupling_basis_matrix).reshape( -1, ) From edfa710da9dc11891e867a290b514842bffb4e1f Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 15 Nov 2024 15:40:11 -0500 Subject: [PATCH 025/107] fixed howto --- docs/how_to_guide/plot_03_population_glm.md | 221 +++++++ docs/how_to_guide/plot_04_batch_glm.md | 246 ++++++++ .../plot_05_sklearn_pipeline_cv_demo.md | 560 ++++++++++++++++++ docs/how_to_guide/plot_06_glm_pytree.md | 354 +++++++++++ 4 files changed, 1381 insertions(+) create mode 100644 docs/how_to_guide/plot_03_population_glm.md create mode 100644 docs/how_to_guide/plot_04_batch_glm.md create mode 100644 docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md create mode 100644 docs/how_to_guide/plot_06_glm_pytree.md diff --git a/docs/how_to_guide/plot_03_population_glm.md b/docs/how_to_guide/plot_03_population_glm.md new file mode 100644 index 00000000..07c90bb6 --- /dev/null +++ b/docs/how_to_guide/plot_03_population_glm.md @@ -0,0 +1,221 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +```{code-cell} ipython3 +%matplotlib inline +``` + + +# Population GLM + +Fitting the activity of a neural population with NeMoS can be much more efficient than fitting each individual +neuron in a loop. The reason for this is that NeMoS leverages the powerful GPU-vectorization implemented by `JAX`. + + +:::{note} +For an unregularized, Lasso, Ridge, or group-Lasso GLM, fitting a GLM one neuron at the time, or fitting jointly +the neural population is equivalent. The main difference between the approaches is that the former is more +memory efficient, the latter is computationally more efficient (it takes less time to fit). +::: + +## Fitting a Population GLM + +NeMoS has a dedicated [`nemos.GLM.PopulationGLM`](nemos.glm.PopulationGLM) class for fitting jointly a neural population. The API + is very similar to that the regular [`GLM`](nemos.glm.GLM), but with a few differences: + + 1. The `y` input to the methods [`fit`](nemos.glm.PopulationGLM.fit) and [`score`](nemos.GLM.PopulationGLM.score) must be a two-dimensional array of shape `(n_samples, n_neurons)`. + 2. You can optionally pass a `feature_mask` in the form of an array of 0s and 1s with shape `(n_features, n_neurons)` + that specifies which features are used as predictors for each neuron. More on this [later](#neuron-specific-features). + +Let's generate some synthetic data and fit a population model. + +```{code-cell} ipython3 +import jax.numpy as jnp +import matplotlib.pyplot as plt + +import numpy as np + +import nemos as nmo + +np.random.seed(123) + +n_features = 5 +n_neurons = 2 +n_samples = 500 + +# random design array. Shape (n_time_points, n_features). +X = 0.5*np.random.normal(size=(n_samples, n_features)) + +# log-rates & weights +b_true = np.zeros((n_neurons, )) +w_true = np.random.uniform(size=(n_features, n_neurons)) + + +# generate counts (spikes will be (n_samples, n_features) +rate = jnp.exp(jnp.dot(X, w_true) + b_true) +spikes = np.random.poisson(rate) + +print(spikes.shape) +``` + +We can now instantiate the [`PopulationGLM`](nemos.glm.PopulationGLM) model and fit. + + +```{code-cell} ipython3 +model = nmo.glm.PopulationGLM() +model.fit(X, spikes) + +print(f"population GLM log-likelihood: {model.score(X, spikes)}") +``` + +## Neuron-specific features +If you want to model neurons with different input features, the way to do so is to specify a `feature_mask`. +Let's assume that we have two neurons, share one shared input, and have an extra private one, for a total of +3 inputs. + + +```{code-cell} ipython3 +# let's take the first three input +n_features = 3 +input_features = X[:, :3] +``` + +Let's assume that: + + - `input_features[:, 0]` is shared. + - `input_features[:, 1]` is an input only for the first neuron. + - `input_features[:, 2]` is an input only for the second neuron. + +We can simulate this scenario, + + +```{code-cell} ipython3 +# model the rate of the first neuron using only the first two features and weights. +rate_neuron_1 = jnp.exp(np.dot(input_features[:, [0, 1]], w_true[: 2, 0])) + +# model the rate of the second neuron using only the first and last feature and weights. +rate_neuron_2 = jnp.exp(np.dot(input_features[:, [0, 2]], w_true[[0, 2], 1])) + +# stack the rates in a (n_samples, n_neurons) array and generate spikes +rate = np.hstack((rate_neuron_1[:, np.newaxis], rate_neuron_2[:, np.newaxis])) +spikes = np.random.poisson(rate) +``` + +We can impose the same constraint to the [`PopulationGLM`](nemos.glm.PopulationGLM) by masking the weights. + + +```{code-cell} ipython3 +# initialize the mask to a matrix of 1s. +feature_mask = np.ones((n_features, n_neurons)) + +# remove the 3rd feature from the predictors of the first neuron +feature_mask[2, 0] = 0 + +# remove the 2nd feature from the predictors of the second neuron +feature_mask[1, 1] = 0 + +# visualize the mask +print(feature_mask) +``` + +The mask can be passed at initialization or set after the model is initialized, but cannot be changed +after the model is fit. + + +```{code-cell} ipython3 +# set a quasi-newton solver and low tolerance for better numerical precision +model = nmo.glm.PopulationGLM(solver_name="LBFGS", solver_kwargs={"tol": 10**-12}) + +# set the mask +model.feature_mask = feature_mask + +# fit the model +model.fit(input_features, spikes) +``` + +If we print the model coefficients, we can see the effect of the mask. + + +```{code-cell} ipython3 +print(model.coef_) +``` + +The coefficient for the first neuron corresponding to the last feature is zero, as well as +the coefficient of the second neuron corresponding to the second feature. + +To convince ourselves that this is equivalent to fit each neuron individually with the correct features, +let's go ahead and try. + + +```{code-cell} ipython3 +# features for each neuron +features_by_neuron = { + 0: [0, 1], + 1: [0, 2] +} +# initialize the coefficients +coeff = np.zeros((2, 2)) + +# loop over the neurons and fit a GLM +for neuron in range(2): + model_neu = nmo.glm.GLM( + solver_name="LBFGS", solver_kwargs={"tol":10**-12} + ) + model_neu.fit(input_features[:, features_by_neuron[neuron]], spikes[:, neuron]) + coeff[:, neuron] = model_neu.coef_ + +# visually compare the estimated coeffeicients +fig, axs = plt.subplots(1, 2, figsize=(6, 3)) +for neuron in range(2): + axs[neuron].set_title(f"neuron {neuron}") + axs[neuron].bar([0, 4], w_true[features_by_neuron[neuron], neuron], width=0.8, label="true") + axs[neuron].bar([1, 5], coeff[:, neuron], width=0.8, label="single neuron GLM") + axs[neuron].bar([2, 6], model.coef_[features_by_neuron[neuron], neuron], width=0.8, label="population GLM") + axs[neuron].set_ylabel("coefficient") + axs[neuron].set_ylim(0, 0.8) + axs[neuron].set_xticks([0.5, 3.5]) + axs[neuron].set_xticklabels(["feature 0", f"feature {neuron + 1}"]) + if neuron == 1: + plt.legend() +plt.tight_layout() +``` + +## FeaturePytree +[`PopulationGLM`](nemos.glm.PopulationGLM) is compatible with [`FeaturePytree`](nemos.pytrees.FeaturePytree). If you structured your predictors +in a [`FeaturePytree`](nemos.pytrees.FeaturePytree), the `feature_mask` needs to be a dictionary of the same structure, containing arrays +of shape `(n_neurons, )`. +The example above can be reformulated as follows, + + +```{code-cell} ipython3 +# restructure the input as FeaturePytree +pytree_features = nmo.pytrees.FeaturePytree( + shared=input_features[:, :1], + neu_0=input_features[:, 1:2], + neu_1=input_features[:, 2:] +) + +# Define a mask as a dictionary +pytree_mask = dict( + shared=np.array([1, 1]), + neu_0=np.array([1, 0]), + neu_1=np.array([0, 1]) +) + +# fit a model +model_tree = nmo.glm.PopulationGLM(solver_name="LBFGS", feature_mask=pytree_mask) +model_tree.fit(pytree_features, spikes) + +# print the coefficients +print(model_tree.coef_) +``` diff --git a/docs/how_to_guide/plot_04_batch_glm.md b/docs/how_to_guide/plot_04_batch_glm.md new file mode 100644 index 00000000..352ea68d --- /dev/null +++ b/docs/how_to_guide/plot_04_batch_glm.md @@ -0,0 +1,246 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +```{code-cell} ipython3 +%matplotlib inline +``` + + +# Batching example + +Here we demonstrate how to setup and run a stochastic gradient descent in `nemos` +by batching and using the [`update`](nemos.glm.GLM.update) method of the model class. + +```{code-cell} ipython3 +import matplotlib.pyplot as plt +import numpy as np +import pynapple as nap + +import nemos as nmo + +nap.nap_config.suppress_conversion_warnings = True + +# set random seed +np.random.seed(123) +``` + +## Simulate data + +Let's generate some data artificially + + +```{code-cell} ipython3 +n_neurons = 10 +T = 50 + +times = np.linspace(0, T, 5000).reshape(-1, 1) +rate = np.exp(np.sin(times + np.linspace(0, np.pi*2, n_neurons).reshape(1, n_neurons))) +``` + +Get the spike times from the rate and generate a `TsGroup` object + + +```{code-cell} ipython3 +spike_t, spike_id = np.where(np.random.poisson(rate)) +units = nap.Tsd(spike_t/T, spike_id).to_tsgroup() +``` + +## Model configuration + +Let's imagine this dataset do not fit in memory. We can use a batching approach to train the GLM. +First we need to instantiate the [`PopulationGLM`](nemos.glm.PopulationGLM) . The default algorithm for [`PopulationGLM`](nemos.glm.PopulationGLM) is gradient descent. +We suggest to use it for batching. + +:::{note} +You must shutdown the dynamic update of the step for fitting a batched (also called stochastic) gradient descent. +In jaxopt, this can be done by setting the parameters `acceleration` to False and setting the `stepsize`. +::: + + +```{code-cell} ipython3 +glm = nmo.glm.PopulationGLM( + solver_name="GradientDescent", + solver_kwargs={"stepsize": 0.1, "acceleration": False} + ) +``` + +## Basis instantiation + +Here we instantiate the basis. `ws` is 40 time bins. It corresponds to a 200 ms windows + + +```{code-cell} ipython3 +ws = 40 +basis = nmo.basis.RaisedCosineBasisLog(5, mode="conv", window_size=ws) +``` + +## Batch definition + +The batch size needs to be larger than the window size of the convolution kernel defined above. + + +```{code-cell} ipython3 +batch_size = 5 # second +``` + +Here we define a batcher function that generate a random 5 s of design matrix and spike counts. +This function will be called during each iteration of the stochastic gradient descent. + + +```{code-cell} ipython3 +def batcher(): + # Grab a random time within the time support. Here is the time support is one epoch only so it's easy. + t = np.random.uniform(units.time_support[0, 0], units.time_support[0, 1]-batch_size) + + # Bin the spike train in a 1s batch + ep = nap.IntervalSet(t, t+batch_size) + counts = units.restrict(ep).count(0.005) # count in 5 ms bins + + # Convolve + X = basis.compute_features(counts) + + # Return X and counts + return X, counts +``` + +## Solver initialization + +First we need to initialize the gradient descent solver within the [`PopulationGLM`](nemos.glm.PopulationGLM) . +This gets you the initial parameters and the first state of the solver. + + +```{code-cell} ipython3 +params = glm.initialize_params(*batcher()) +state = glm.initialize_state(*batcher(), params) +``` + +## Batch learning + +Let's do a few iterations of gradient descent calling the `batcher` function at every step. +At each step, we store the log-likelihood of the model for each neuron evaluated on the batch + + +```{code-cell} ipython3 +n_step = 500 +logl = np.zeros(n_step) + +for i in range(n_step): + + # Get a batch of data + X, Y = batcher() + + # Do one step of gradient descent. + params, state = glm.update(params, state, X, Y) + + # Score the model along the time axis + logl[i] = glm.score(X, Y, score_type="log-likelihood") +``` + +:::{admonition} Input validation +:class: warning + +The `update` method does not perform input validation each time it is called. +This design choice speeds up computation by avoiding repetitive checks. However, +it requires that all inputs to the `update` method strictly conform to the expected +dimensionality and structure as established during the initialization of the solver. +Failure to comply with these expectations will likely result in runtime errors or +incorrect computations. +::: + +First let's plot the log-likelihood to see if the model is converging. + + +```{code-cell} ipython3 +plt.figure() +plt.plot(logl) +plt.xlabel("Iteration") +plt.ylabel("Log-likelihood") +plt.show() +``` + +We can see that the log-likelihood is increasing but did not reach plateau yet. +The number of iterations can be increased to continue learning. + +We can take a look at the coefficients. +Here we extract the weight matrix of shape `(n_neurons*n_basis, n_neurons)` +and reshape it to `(n_neurons, n_basis, n_neurons)`. +We then average along basis to get a weight matrix of shape `(n_neurons, n_neurons)`. + + +```{code-cell} ipython3 +W = glm.coef_.reshape(len(units), basis.n_basis_funcs, len(units)) +Wm = np.mean(np.abs(W), 1) + +# Let's plot it. + +plt.figure() +plt.imshow(Wm) +plt.xlabel("Neurons") +plt.ylabel("Neurons") +plt.show() +``` + +## Model comparison + +Since this example is small enough, we can fit the full model and compare the scores. +Here we generate the design matrix and spike counts for the whole dataset. + + +```{code-cell} ipython3 +Y = units.count(0.005) +X = basis.compute_features(Y) +full_model = nmo.glm.PopulationGLM().fit(X, Y) +``` + +Now that the full model is fitted, we are scoring the full model and the batch model against the full datasets to compare the scores. +The score is pseudo-R2 + + +```{code-cell} ipython3 +full_scores = full_model.score( + X, Y, aggregate_sample_scores=lambda x:np.mean(x, axis=0), score_type="pseudo-r2-McFadden" +) +batch_scores = glm.score( + X, Y, aggregate_sample_scores=lambda x:np.mean(x, axis=0), score_type="pseudo-r2-McFadden" +) +``` + +Let's compare scores for each neurons as well as the coefficients. + + +```{code-cell} ipython3 +plt.figure(figsize=(10, 8)) +gs = plt.GridSpec(3,2) +plt.subplot(gs[0,:]) +plt.bar(np.arange(0, n_neurons), full_scores, 0.4, label="Full model") +plt.bar(np.arange(0, n_neurons)+0.5, batch_scores, 0.4, label="Batch model") +plt.ylabel("Pseudo R2") +plt.xlabel("Neurons") +plt.ylim(0, 1) +plt.legend() +plt.subplot(gs[1:,0]) +plt.imshow(Wm) +plt.title("Batch model") +plt.subplot(gs[1:,1]) +Wm2 = np.mean( + np.abs( + full_model.coef_.reshape(len(units), basis.n_basis_funcs, len(units)) + ) + , 1) +plt.imshow(Wm2) +plt.title("Full model") +plt.tight_layout() +plt.show() +``` + +As we can see, with a few iterations, the batch model manage to recover a similar coefficient matrix. diff --git a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md new file mode 100644 index 00000000..6aa7df5b --- /dev/null +++ b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md @@ -0,0 +1,560 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +```{code-cell} ipython3 +%matplotlib inline +``` + + +# Selecting basis by cross-validation with scikit-learn + +In this demo, we will demonstrate how to select an appropriate basis and its hyperparameters using cross-validation. +In particular, we will learn: + +1. What a scikit-learn pipeline is. +2. Why pipelines are useful. +3. How to combine NeMoS [`Basis`](nemos.basis.Basis) and [`GLM`](nemos.glm.GLM) objects in a pipeline. +4. How to select the number of bases and the basis type through cross-validation (or any other hyperparameter in the pipeline). +5. How to use a custom scoring metric to quantify the performance of each configuration. + ++++ + +## What is a scikit-learn pipeline + +
+Pipeline illustration. +
Schematic of a scikit-learn pipeline.
+
+ +A pipeline is a sequence of data transformations leading up to a model. Each step before the final one transforms the input data into a different representation, and then the final model step fits, predicts, or scores based on the previous step's output and some observations. Setting up such machinery can be simplified using the [`Pipeline`](https://scikit-learn.org/1.5/modules/generated/sklearn.pipeline.Pipeline.html) class from scikit-learn. + +To set up a scikit-learn [`Pipeline`](https://scikit-learn.org/1.5/modules/generated/sklearn.pipeline.Pipeline.html), ensure that: + +1. Each intermediate step is a [scikit-learn transformer object](https://scikit-learn.org/stable/data_transforms.html) with a `transform` and/or `fit_transform` method. +2. The final step is an [estimator object](https://scikit-learn.org/stable/developers/develop.html#estimators) with a `fit` method, or a model with `fit`, `predict`, and `score` methods. + +Each transformation step takes a 2D array `X` of shape `(num_samples, num_original_features)` as input and outputs another 2D array of shape `(num_samples, num_transformed_features)`. The final step takes a pair `(X, y)`, where `X` is as before, and `y` is a 1D array of shape `(n_samples,)` containing the observations to be modeled. + +You can define a pipeline as follows: +```python +from sklearn.pipeline import Pipeline + +# Assume transformer_i/predictor is a transformer/model object +pipe = Pipeline( + [ + ("label_1", transformer_1), + ("label_2", transformer_2), + ..., + ("label_n", transformer_n), + ("label_model", model) + ] +) +``` + +Note that you have to assign a label to each step of the pipeline. +:::{tip} +Here we used a placeholder `"label_i"` for demonstration; you should choose a more descriptive name depending on the type of transformation step. +::: + +Calling `pipe.fit(X, y)` will perform the following computations: +```python +# Chain of transformations +X1 = transformer_1.fit_transform(X) +X2 = transformer_2.fit_transform(X1) +# ... +Xn = transformer_n.fit_transform(Xn_1) + +# Fit step +model.fit(Xn, y) +``` +And the same holds for `pipe.score` and `pipe.predict`. + +## Why pipelines are useful + +Pipelines not only streamline and simplify your code but also offer several other advantages. The real power of pipelines becomes evident when combined with the scikit-learn [`model_selection`](https://scikit-learn.org/1.5/api/sklearn.model_selection.html) module, which includes cross-validation and similar methods. This combination allows you to tune hyperparameters at each step of the pipeline in a straightforward manner. + +In the following sections, we will showcase this approach with a concrete example: selecting the appropriate basis type and number of bases for a GLM regression in NeMoS. + +## Combining basis transformations and GLM in a pipeline +Let's start by creating some toy data. + + +```{code-cell} ipython3 +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import scipy.stats +import seaborn as sns +from sklearn.model_selection import GridSearchCV +from sklearn.pipeline import Pipeline + +import nemos as nmo + +# some helper plotting functions +from nemos import _documentation_utils as doc_plots + +# predictors, shape (n_samples, n_features) +X = np.random.uniform(low=0, high=1, size=(1000, 1)) +# observed counts, shape (n_samples,) +rate = 2 * ( + scipy.stats.norm.pdf(X, scale=0.1, loc=0.25) + + scipy.stats.norm.pdf(X, scale=0.1, loc=0.75) +) +y = np.random.poisson(rate).astype(float).flatten() +``` + +Let's now plot the simulated neuron's tuning curve, which is bimodal, Gaussian-shaped, and has peaks at 0.25 and 0.75. + + +```{code-cell} ipython3 +fig, ax = plt.subplots() +ax.scatter(X.flatten(), y, alpha=0.2) +ax.set_xlabel("input") +ax.set_ylabel("spike count") +sns.despine(ax=ax) +``` + +### Converting NeMoS `Basis` to a transformer +In order to use NeMoS [`Basis`](nemos.basis.Basis) in a pipeline, we need to convert it into a scikit-learn transformer. This can be achieved through the [`TransformerBasis`](nemos.basis.TransformerBasis) wrapper class. + +Instantiating a [`TransformerBasis`](nemos.basis.TransformerBasis) can be done either using the constructor directly or with [`Basis.to_transformer()`](nemos.basis.Basis.to_transformer): + + +```{code-cell} ipython3 +bas = nmo.basis.RaisedCosineBasisLinear(5, mode="conv", window_size=5) +# these two ways of creating the TransformerBasis are equivalent +trans_bas_a = nmo.basis.TransformerBasis(bas) +trans_bas_b = bas.to_transformer() +``` + +[`TransformerBasis`](nemos.basis.TransformerBasis) provides convenient access to the underlying [`Basis`](nemos.basis.Basis) object's attributes: + + +```{code-cell} ipython3 +print(bas.n_basis_funcs, trans_bas_a.n_basis_funcs, trans_bas_b.n_basis_funcs) +``` + +We can also set attributes of the underlying [`Basis`](nemos.basis.Basis). Note that -- because [`TransformerBasis`](nemos.basis.TransformerBasis) is created with a copy of the [`Basis`](nemos.basis.Basis) object passed to it -- this does not change the original [`Basis`](nemos.basis.Basis), and neither does changing the original [`Basis`](nemos.basis.Basis) change [`TransformerBasis`](nemos.basis.TransformerBasis) we created: + + +```{code-cell} ipython3 +trans_bas_a.n_basis_funcs = 10 +bas.n_basis_funcs = 100 + +print(bas.n_basis_funcs, trans_bas_a.n_basis_funcs, trans_bas_b.n_basis_funcs) +``` + +### Creating and fitting a pipeline +We might want to combine first transforming the input data with our basis functions, then fitting a GLM on the transformed data. + +This is exactly what `Pipeline` is for! + + +```{code-cell} ipython3 +pipeline = Pipeline( + [ + ( + "transformerbasis", + nmo.basis.TransformerBasis(nmo.basis.RaisedCosineBasisLinear(6)), + ), + ( + "glm", + nmo.glm.GLM(regularizer_strength=0.5, regularizer="Ridge"), + ), + ] +) + +pipeline.fit(X, y) +``` + +Note how NeMoS models are already scikit-learn compatible and can be used directly in the pipeline. + +Visualize the fit: + + +```{code-cell} ipython3 +# Predict the rate. +# Note that you need a 2D input even if x is a flat array. +# We are using expand dim to add the extra-dimension +x = np.sort(X, axis=0) +predicted_rate = pipeline.predict(x) +``` + +```{code-cell} ipython3 +fig, ax = plt.subplots() + +ax.scatter(X.flatten(), y, alpha=0.2, label="generated spike counts") +ax.set_xlabel("input") +ax.set_ylabel("spike count") + + +ax.plot( + x, + predicted_rate, + label="predicted rate", + color="tab:orange", +) + +ax.legend() +sns.despine(ax=ax) +``` + +The current model captures the bimodal distribution of responses, appropriately picking out the peaks. However, it doesn't do a good job capturing the actual firing rate: the peaks are too low and the valleys are not low enough. This might be because of our choice of basis and/or regularizer strength, so let's see if tuning those parameters results in a better fit! We could do this manually, but doing this with the sklearn pipeline will make everything much easier! + + ++++ + +### Select the number of basis by cross-validation + + ++++ + +:::{warning} +Please keep in mind that while [`GLM.score`](nemos.glm.GLM.score) supports different ways of evaluating goodness-of-fit through the `score_type` argument, `pipeline.score(X, y, score_type="...")` does not propagate this, and uses the default value of `log-likelihood`. + +To evaluate a pipeline, please create a custom scorer (e.g. `pseudo_r2` below) and call `my_custom_scorer(pipeline, X, y)`. +::: + +#### Define the parameter grid + +Let's define candidate values for the parameters of each step of the pipeline we want to cross-validate. In this case the number of basis functions in the transformation step and the ridge regularization's strength in the GLM fit: + + +```{code-cell} ipython3 +param_grid = dict( + glm__regularizer_strength=(0.1, 0.01, 0.001, 1e-6), + transformerbasis__n_basis_funcs=(3, 5, 10, 20, 100), +) +``` + +:::{admonition} Grid definition +:class: info +In order to define a parameter grid dictionary for a pipeline, you must structure the dictionary keys as follows: + +- Start with the pipeline label (`"glm"` or `"transformerbasis"` for us). This determines which pipeline step has the relevant hyperparameter. +- Add `"__"` followed by the hyperparameter name (for example, `"n_basis_funcs"`). +- If the hyperparameter is itself an object with attributes, add another `"__"` followed by the attribute name. For instance, `"glm__observation_model__inverse_link_function"` + would be a valid key for cross-validating over the link function of the GLM's `observation_model` attribute `inverse_link_function`. +The values in the dictionary are the parameters to be tested. +::: + ++++ + +#### Run the grid search +Let's run a 5-fold cross-validation of the hyperparameters with the scikit-learn [`model_selection.GridsearchCV`](https://scikit-learn.org/1.5/modules/generated/sklearn.model_selection.GridSearchCV.html#sklearn.model_selection.GridSearchCV) class. +:::{dropdown} K-Fold cross-validation +:color: info +:icon: info + +

+Grid Search Cross Validation +
+K-fold cross-validation (modified from scikit-learn docs) +

+K-fold cross-validation is a robust method used for selecting hyperparameters. In this procedure, the data is divided into K equally sized chunks (or folds). The model is trained on K-1 of these chunks, with the remaining chunk used for evaluation. This process is repeated K times, with each chunk being used exactly once as the evaluation set. +After completing the K iterations, the K evaluation scores are averaged to provide a reliable estimate of the model's performance. To select the optimal hyperparameters, K-fold cross-validation can be applied over a grid of potential hyperparameters, with the set yielding the highest average score being chosen as the best. +::: + +```{code-cell} ipython3 +gridsearch = GridSearchCV( + pipeline, + param_grid=param_grid, + cv=5 +) + +# run the 5-fold cross-validation grid search +gridsearch.fit(X, y) +``` + +:::{dropdown} Manual cross-validation +:color: info +:icon: info +To appreciate how much boiler-plate code we are saving by calling scikit-learn cross-validation, below +we can see how this cross-validation will look like in a manual loop. + +```python +from itertools import product +from copy import deepcopy + +regularizer_strength = (0.1, 0.01, 0.001, 1e-6) +n_basis_funcs = (3, 5, 10, 20, 100) + +# define the folds +n_folds = 5 +fold_idx = np.arange(X.shape[0] - X.shape[0] % n_folds).reshape(n_folds, -1) + + +# Initialize the scores +scores = np.zeros((len(regularizer_strength) * len(n_basis_funcs), n_folds)) + +# Dictionary to store coefficients +coeffs = {} + +# initialize basis and model +basis = nmo.basis.TransformerBasis(nmo.basis.RaisedCosineBasisLinear(6)) +model = nmo.glm.GLM(regularizer="Ridge") + +# loop over combinations +for fold in range(n_folds): + test_idx = fold_idx[fold] + train_idx = fold_idx[[x for x in range(n_folds) if x != fold]].flatten() + for i, params in enumerate(product(regularizer_strength, n_basis_funcs)): + reg_strength, n_basis = params + + # deepcopy the basis and model + bas = deepcopy(basis) + glm = deepcopy(model) + + # set the parameters + bas.n_basis_funcs = n_basis + glm.regularizer_strength = reg_strength + + # fit the model + glm.fit(bas.transform(X[train_idx]), y[train_idx]) + + # store score and coefficients + scores[i, fold] = glm.score(bas.transform(X[test_idx]), y[test_idx]) + coeffs[(i, fold)] = (glm.coef_, glm.intercept_) + +# get the best mean test score +i_best = np.argmax(scores.mean(axis=1)) +# get the overall best coeffs +fold_best = np.argmax(scores[i_best]) + +# set up the best model +model.coef_ = coeffs[(i_best, fold_best)][0] +model.intercept_ = coeffs[(i_best, fold_best)][1] + +# get the best hyperparameters +best_reg_strength = regularizer_strength[i_best // len(n_basis_funcs)] +best_n_basis = n_basis_funcs[i_best % len(n_basis_funcs)] +``` +::: + ++++ + +#### Visualize the scores + +Let's extract the scores from `gridsearch` and take a look at how the different parameter values of our pipeline influence the test score: + + +```{code-cell} ipython3 +cvdf = pd.DataFrame(gridsearch.cv_results_) + +cvdf_wide = cvdf.pivot( + index="param_transformerbasis__n_basis_funcs", + columns="param_glm__regularizer_strength", + values="mean_test_score", +) + +doc_plots.plot_heatmap_cv_results(cvdf_wide) +``` + +The plot displays the model's log-likelihood for each parameter combination in the grid. The parameter combination with the highest score, which is the one selected by the procedure, is highlighted with a blue rectangle. We can thus see that we need 10 or more basis functions, and that all of the tested regularization strengths agree with each other. In general, we want the fewest number of basis functions required to get a good fit, so we'll choose 10 here. + +#### Visualize the predicted rate +Finally, visualize the predicted firing rates using the best model found by our grid-search, which gives a better fit than the randomly chosen parameter values we tried in the beginning: + + +```{code-cell} ipython3 +# Predict the ate using the best configuration, +x = np.sort(X, axis=0) +predicted_rate = gridsearch.best_estimator_.predict(x) +``` + +```{code-cell} ipython3 +fig, ax = plt.subplots() + +ax.scatter(X.flatten(), y, alpha=0.2, label="generated spike counts") +ax.set_xlabel("input") +ax.set_ylabel("spike count") + + +ax.plot( + x, + predicted_rate, + label="predicted rate", + color="tab:orange", +) + +ax.legend() +sns.despine(ax=ax) +``` + +:rocket::rocket::rocket: **Success!** :rocket::rocket::rocket: +We are now able to capture the distribution of the firing rate appropriately: both peaks and valleys in the spiking activity are matched by our model predicitons. + +### Evaluating different bases directly + +In the previous example we set the number of basis functions of the [`Basis`](nemos.basis.Basis) wrapped in our [`TransformerBasis`](nemos.basis.TransformerBasis). However, if we are for example not sure about the type of basis functions we want to use, or we have already defined some basis functions of our own, then we can use cross-validation to directly evaluate those as well. + +Here we include `transformerbasis___basis` in the parameter grid to try different values for `TransformerBasis._basis`: + + +```{code-cell} ipython3 +param_grid = dict( + glm__regularizer_strength=(0.1, 0.01, 0.001, 1e-6), + transformerbasis___basis=( + nmo.basis.RaisedCosineBasisLinear(5), + nmo.basis.RaisedCosineBasisLinear(10), + nmo.basis.RaisedCosineBasisLog(5), + nmo.basis.RaisedCosineBasisLog(10), + nmo.basis.MSplineBasis(5), + nmo.basis.MSplineBasis(10), + ), +) +``` + +Then run the grid search: + + +```{code-cell} ipython3 +gridsearch = GridSearchCV( + pipeline, + param_grid=param_grid, + cv=5, +) + +# run the 5-fold cross-validation grid search +gridsearch.fit(X, y) +``` + +Wrangling the output data a bit and looking at the scores: + + +```{code-cell} ipython3 +cvdf = pd.DataFrame(gridsearch.cv_results_) + +# Read out the number of basis functions +cvdf["transformerbasis_config"] = [ + f"{b.__class__.__name__} - {b.n_basis_funcs}" + for b in cvdf["param_transformerbasis___basis"] +] + +cvdf_wide = cvdf.pivot( + index="transformerbasis_config", + columns="param_glm__regularizer_strength", + values="mean_test_score", +) + +doc_plots.plot_heatmap_cv_results(cvdf_wide) +``` + +As shown in the table, the model with the highest score, highlighted in blue, used a RaisedCosineBasisLinear basis (as used above), which appears to be a suitable choice for our toy data. +We can confirm that by plotting the firing rate predictions: + + +```{code-cell} ipython3 +# Predict the rate using the optimal configuration +x = np.sort(X, axis=0) +predicted_rate = gridsearch.best_estimator_.predict(x) +``` + +```{code-cell} ipython3 +fig, ax = plt.subplots() + +ax.scatter(X.flatten(), y, alpha=0.2, label="generated spike counts") +ax.set_xlabel("input") +ax.set_ylabel("spike count") + +ax.plot( + x, + predicted_rate, + label="predicted rate", + color="tab:orange", +) + +ax.legend() +sns.despine(ax=ax) +``` + +The plot confirms that the firing rate distribution is accurately captured by our model predictions. + + ++++ + +!!! warning + Please note that because it would lead to unexpected behavior, mixing the two ways of defining values for the parameter grid is not allowed. The following would lead to an error: + + ```python + param_grid = dict( + glm__regularizer_strength=(0.1, 0.01, 0.001, 1e-6), + transformerbasis__n_basis_funcs=(3, 5, 10, 20, 100), + transformerbasis___basis=( + nmo.basis.RaisedCosineBasisLinear(5), + nmo.basis.RaisedCosineBasisLinear(10), + nmo.basis.RaisedCosineBasisLog(5), + nmo.basis.RaisedCosineBasisLog(10), + nmo.basis.MSplineBasis(5), + nmo.basis.MSplineBasis(10), + ), + ) + ``` + + ++++ + +## Create a custom scorer +By default, the GLM score method returns the model log-likelihood. If you want to try a different metric, such as the pseudo-R2, you can create a custom scorer and pass it to the cross-validation object: + + +```{code-cell} ipython3 +from sklearn.metrics import make_scorer + +pseudo_r2 = make_scorer( + nmo.observation_models.PoissonObservations().pseudo_r2 +) +``` + +We can now run the grid search providing the custom scorer + + +```{code-cell} ipython3 +gridsearch = GridSearchCV( + pipeline, + param_grid=param_grid, + cv=5, + scoring=pseudo_r2, +) + +# Run the 5-fold cross-validation grid search +gridsearch.fit(X, y) +``` + +And finally, we can plot each model's score. + + ++++ + +Plot the pseudo-R2 scores + + +```{code-cell} ipython3 +cvdf = pd.DataFrame(gridsearch.cv_results_) + +# Read out the number of basis functions +cvdf["transformerbasis_config"] = [ + f"{b.__class__.__name__} - {b.n_basis_funcs}" + for b in cvdf["param_transformerbasis___basis"] +] + +cvdf_wide = cvdf.pivot( + index="transformerbasis_config", + columns="param_glm__regularizer_strength", + values="mean_test_score", +) + +doc_plots.plot_heatmap_cv_results(cvdf_wide, label="pseudo-R2") +``` + +As you can see, the results with pseudo-R2 agree with those of the negative log-likelihood. Note that this new metric is normalized between 0 and 1, with a higher score indicating better performance. diff --git a/docs/how_to_guide/plot_06_glm_pytree.md b/docs/how_to_guide/plot_06_glm_pytree.md new file mode 100644 index 00000000..92a8a18e --- /dev/null +++ b/docs/how_to_guide/plot_06_glm_pytree.md @@ -0,0 +1,354 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +```{code-cell} ipython3 +%matplotlib inline +``` + +# FeaturePytree example + +This small example notebook shows how to use our custom FeaturePytree objects +instead of arrays to represent the design matrix. It will show that these two +representations are equivalent. + +This demo will fit the Poisson-GLM to some synthetic data. We will first show +the simple case, with a single neuron receiving some input. We will then show a +two-neuron system, to demonstrate how FeaturePytree can make it easier to +separate examine separate types of inputs. + +First, however, let's briefly discuss [`FeaturePytrees`](nemos.pytrees.FeaturePytree). + +```{code-cell} ipython3 +import jax +import jax.numpy as jnp +import numpy as np + +import nemos as nmo + +np.random.seed(111) +``` + +## FeaturePytrees + +A FeaturePytree is a custom NeMoS object used to represent design matrices, +GLM coefficients, and other similar variables. It is a simple +[pytree](https://jax.readthedocs.io/en/latest/pytrees.html), a dictionary +with strings as keys and arrays as values. These arrays must all have the +same number of elements along the first dimension, which represents the time +points, but can have different numbers of elements along the other dimensions +(and even different numbers of dimensions). + + +```{code-cell} ipython3 +example_pytree = nmo.pytrees.FeaturePytree(feature_0=np.random.normal(size=(100, 1, 2)), + feature_1=np.random.normal(size=(100, 2)), + feature_2=np.random.normal(size=(100, 5))) +example_pytree +``` + +FeaturePytrees can be indexed into like dictionary, so we can grab a +single one of their features: + + +```{code-cell} ipython3 +example_pytree['feature_0'].shape +``` + +We can grab the number of time points by getting the length or using the +`shape` attribute + + +```{code-cell} ipython3 +print(len(example_pytree)) +print(example_pytree.shape) +``` + +We can also jointly index into the FeaturePytree's leaves: + + +```{code-cell} ipython3 +example_pytree[:10] +``` + +We can add new features after initialization, as long as they have the same +number of time points. + + +```{code-cell} ipython3 +example_pytree['feature_3'] = np.zeros((100, 2, 4)) +``` + +However, if we try to add a new feature with the wrong number of time points, +we'll get an exception: + + +```{code-cell} ipython3 +try: + example_pytree['feature_4'] = np.zeros((99, 2, 4)) +except ValueError as e: + print(e) +``` + +Similarly, if we try to add a feature that's not an array: + + +```{code-cell} ipython3 +try: + example_pytree['feature_4'] = "Strings are very predictive" +except ValueError as e: + print(e) +``` + +FeaturePytrees are intended to be used with +[jax.tree_util.tree_map](https://jax.readthedocs.io/en/latest/_autosummary/jax.tree_util.tree_map.html), +a useful function for performing computations on arbitrary pytrees, +preserving their structure. + + ++++ + +We can map lambda functions: + + +```{code-cell} ipython3 +mapped = jax.tree_util.tree_map(lambda x: x**2, example_pytree) +print(mapped) +mapped['feature_1'] +``` + +Or functions from jax or numpy that operate on arrays: + + +```{code-cell} ipython3 +mapped = jax.tree_util.tree_map(jnp.exp, example_pytree) +print(mapped) +mapped['feature_1'] +``` + +We can change the dimensionality of our pytree: + + +```{code-cell} ipython3 +mapped = jax.tree_util.tree_map(lambda x: jnp.mean(x, axis=-1), example_pytree) +print(mapped) +mapped['feature_1'] +``` + +Or the number of time points: + + +```{code-cell} ipython3 +mapped = jax.tree_util.tree_map(lambda x: x[::10], example_pytree) +print(mapped) +mapped['feature_1'] +``` + +If we map something whose output cannot be a FeaturePytree (because its +values are scalars or non-arrays), we return a dictionary of arrays instead: + + +```{code-cell} ipython3 +print(jax.tree_util.tree_map(jnp.mean, example_pytree)) +print(jax.tree_util.tree_map(lambda x: x.shape, example_pytree)) +import matplotlib.pyplot as plt +import pynapple as nap +``` + +## FeaturePytrees and GLM + +These properties make FeaturePytrees useful for representing design matrices +and similar objects for the [`GLM`](nemos.glm.GLM). + +First, let's get our dataset and do some initial exploration of it. To do so, +we'll use pynapple to [stream +data](https://pynapple.org/examples/tutorial_pynapple_dandi.html) +from the DANDI archive. + +:::{attention} + +We need some additional packages for this portion, which you can install +with `pip install dandi pynapple` +::: + +```{code-cell} ipython3 +io = nmo.fetch.download_dandi_data( + "000582", + "sub-11265/sub-11265_ses-07020602_behavior+ecephys.nwb", +) + +nwb = nap.NWBFile(io.read(), lazy_loading=False) + +print(nwb) +``` + +This data set has cells that are tuned for head direction and 2d position. +Let's compute some simple tuning curves to see if we can find a cell that +looks tuned for both. + + +```{code-cell} ipython3 +tc, binsxy = nap.compute_2d_tuning_curves(nwb['units'], nwb['SpatialSeriesLED1'].dropna(), 20) +fig, axes = plt.subplots(3, 3, figsize=(9, 9)) +for i, ax in zip(tc.keys(), axes.flatten()): + ax.imshow(tc[i], origin="lower", aspect="auto") + ax.set_title("Unit {}".format(i)) +axes[-1,-1].remove() +plt.tight_layout() + +# compute head direction. +diff = nwb['SpatialSeriesLED1'].values-nwb['SpatialSeriesLED2'].values +head_dir = np.arctan2(*diff.T) +head_dir = nap.Tsd(nwb['SpatialSeriesLED1'].index, head_dir) + +tune_head = nap.compute_1d_tuning_curves(nwb['units'], head_dir.dropna(), 30) + +fig, axes = plt.subplots(3, 3, figsize=(9, 9), subplot_kw={'projection': 'polar'}) +for i, ax in zip(tune_head.columns, axes.flatten()): + ax.plot(tune_head.index, tune_head[i]) + ax.set_title("Unit {}".format(i)) +axes[-1,-1].remove() +``` + +Okay, let's use unit number 7. + +Now let's set up our design matrix. First, let's fit the head direction by +itself. Head direction is a circular variable (pi and -pi are adjacent to +each other), so we need to use a basis that has this property as well. +[`CyclicBSplineBasis`](nemos.basis.CyclicBSplineBasis) is one such basis. + +Let's create our basis and then arrange our data properly. + + +```{code-cell} ipython3 +unit_no = 7 +spikes = nwb['units'][unit_no] + +basis = nmo.basis.CyclicBSplineBasis(10, order=5) +x = np.linspace(-np.pi, np.pi, 100) +plt.figure() +plt.plot(x, basis(x)) + +# Find the interval on which head_dir has no NaNs +head_dir = head_dir.dropna() +# Grab the second (of two), since the first one is really short +valid_data= head_dir.time_support.loc[[1]] +head_dir = head_dir.restrict(valid_data) +# Count spikes at the same rate as head direction, over the same epoch +spikes = spikes.count(bin_size=1/head_dir.rate, ep=valid_data) +# the time points for spike are in the middle of these bins (whereas for +# head_dir they're at the ends), so use interpolate to shift head_dir to the +# center. +head_dir = head_dir.interpolate(spikes) + +X = nmo.pytrees.FeaturePytree(head_direction=basis(head_dir)) +``` + +Now we'll fit our GLM and then see what our head direction tuning looks like: + + +```{code-cell} ipython3 +model = nmo.glm.GLM(regularizer="Ridge", regularizer_strength=0.001) +model.fit(X, spikes) +print(model.coef_['head_direction']) + +bs_vis = basis(x) +tuning = jnp.einsum('b, tb->t', model.coef_['head_direction'], bs_vis) +plt.figure() +plt.polar(x, tuning) +``` + +This looks like a smoothed version of our tuning curve, like we'd expect! + +For a more direct comparison, we can plot the tuning function based on the model predicted +firing rates with that estimated from the counts. + + +```{code-cell} ipython3 +# predict rates and convert back to pynapple +rates_nap = nap.TsdFrame(t=head_dir.t, d=np.asarray(model.predict(X))) +# compute tuning function +tune_head_model = nap.compute_1d_tuning_curves_continuous(rates_nap, head_dir, 30) +# compare model prediction with data +fig, ax = plt.subplots(1, 1, subplot_kw={'projection': 'polar'}) +ax.plot(tune_head[7], label="counts") +# multiply by the sampling rate for converting to spike/sec. +ax.plot(tune_head_model * rates_nap.rate, label="model") + +# Let's compare this to using arrays, to see what it looks like: + +model = nmo.glm.GLM() +model.fit(X['head_direction'], spikes) +model.coef_ +``` + +We can see that the solution is identical, as is the way of interacting with +the GLM object. + +However, with a single type of feature, it's unclear why exactly this is +helpful. Let's add a feature for the animal's position in space. For this +feature, we need a 2d basis. Let's use some raised cosine bumps and organize +our data similarly. + + +```{code-cell} ipython3 +pos_basis = nmo.basis.RaisedCosineBasisLinear(10) * nmo.basis.RaisedCosineBasisLinear(10) +spatial_pos = nwb['SpatialSeriesLED1'].restrict(valid_data) + +X['spatial_position'] = pos_basis(*spatial_pos.values.T) +``` + +Running the GLM is identical to before, but we can see that our coef_ +FeaturePytree now has two separate keys, one for each feature type. + + +```{code-cell} ipython3 +model = nmo.glm.GLM(solver_name="LBFGS") +model.fit(X, spikes) +model.coef_ +``` + +Let's visualize our tuning. Head direction looks pretty much the same (though +the values are slightly different, as we can see when printing out the +coefficients). + + +```{code-cell} ipython3 +bs_vis = basis(x) +tuning = jnp.einsum('b,nb->n', model.coef_['head_direction'], bs_vis) +print(model.coef_['head_direction']) +plt.figure() +plt.polar(x, tuning.T) +``` + +And the spatial tuning again looks like a smoothed version of our earlier +tuning curves. + + +```{code-cell} ipython3 +_, _, pos_bs_vis = pos_basis.evaluate_on_grid(50, 50) +pos_tuning = jnp.einsum('b,ijb->ij', model.coef_['spatial_position'], pos_bs_vis) +plt.figure() +plt.imshow(pos_tuning) +``` + +We could do all this with matrices as well, but we have to pay attention to +indices in a way that is annoying: + + +```{code-cell} ipython3 +X_mat = nmo.utils.pynapple_concatenate_jax([X['head_direction'], X['spatial_position']], -1) + +model = nmo.glm.GLM() +model.fit(X_mat, spikes) +model.coef_[..., :basis.n_basis_funcs] +``` From f993b7197bfb1f9ef0b85285d438184a580f9d19 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 15 Nov 2024 15:40:47 -0500 Subject: [PATCH 026/107] finished howto, started tutorials --- docs/api_guide.rst | 18 + docs/conf.py | 4 +- docs/how_to_guide/README.md | 8 +- docs/how_to_guide/plot_02_glm_demo.md | 39 +- docs/how_to_guide/plot_03_glm_pytree.md | 354 ----------- docs/how_to_guide/plot_04_population_glm.md | 219 ------- docs/how_to_guide/plot_05_batch_glm.md | 243 -------- .../plot_06_sklearn_pipeline_cv_demo.md | 552 ------------------ docs/tutorials/README.md | 27 +- docs/tutorials/plot_01_current_injection.md | 129 ++-- pyproject.toml | 1 + src/nemos/observation_models.py | 13 +- 12 files changed, 144 insertions(+), 1463 deletions(-) delete mode 100644 docs/how_to_guide/plot_03_glm_pytree.md delete mode 100644 docs/how_to_guide/plot_04_population_glm.md delete mode 100644 docs/how_to_guide/plot_05_batch_glm.md delete mode 100644 docs/how_to_guide/plot_06_sklearn_pipeline_cv_demo.md diff --git a/docs/api_guide.rst b/docs/api_guide.rst index f727f1a8..9dd52137 100644 --- a/docs/api_guide.rst +++ b/docs/api_guide.rst @@ -40,6 +40,7 @@ Provides basis function classes to construct and transform features for model in MultiplicativeBasis TransformerBasis +.. _observation_models: The ``nemos.observation_models`` module -------------------------------------- Statistical models to describe the distribution of neural responses or other predicted variables, given inputs. @@ -51,9 +52,11 @@ Statistical models to describe the distribution of neural responses or other pre :recursive: :nosignatures: + Observations PoissonObservations GammaObservations +.. _regularizers: The ``nemos.regularizer`` module -------------------------------- Implements various regularization techniques to constrain model parameters, which helps prevent overfitting. @@ -65,6 +68,7 @@ Implements various regularization techniques to constrain model parameters, whic :recursive: :nosignatures: + Regularizer UnRegularized Ridge Lasso @@ -115,3 +119,17 @@ solutions. apply_identifiability_constraints apply_identifiability_constraints_by_basis_component + +The ``nemos.pytrees.FeaturePytree`` class +----------------------------------------- +Class for storing the input arrays in a dictionary. Keys are usually variable names. +These objects can be provided as input to nemos GLM methods. + +.. currentmodule:: nemos.pytrees + +.. autosummary:: + :toctree: generated/identifiability_constraints + :recursive: + :nosignatures: + + FeaturePytree diff --git a/docs/conf.py b/docs/conf.py index 26aa9f06..56f71b56 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -42,9 +42,9 @@ extensions = [ 'sphinx.ext.autodoc', - #'numpydoc', 'sphinx.ext.napoleon', 'sphinx.ext.autosummary', + 'sphinxemoji.sphinxemoji', 'sphinx.ext.coverage', 'sphinx.ext.viewcode', # Links to source code 'sphinx.ext.doctest', @@ -163,4 +163,6 @@ copybutton_prompt_text = r">>> |\$ |# " copybutton_prompt_is_regexp = True +sphinxemoji_style = 'twemoji' + nitpicky = True diff --git a/docs/how_to_guide/README.md b/docs/how_to_guide/README.md index 1b919c70..a7a5a231 100644 --- a/docs/how_to_guide/README.md +++ b/docs/how_to_guide/README.md @@ -19,8 +19,8 @@ pip install nemos[examples] :caption: Contents plot_02_glm_demo.md -plot_04_population_glm.md -plot_05_batch_glm.md -plot_06_sklearn_pipeline_cv_demo.md -plot_03_glm_pytree.md +plot_03_population_glm.md +plot_04_batch_glm.md +plot_05_sklearn_pipeline_cv_demo.md +plot_06_glm_pytree.md ``` \ No newline at end of file diff --git a/docs/how_to_guide/plot_02_glm_demo.md b/docs/how_to_guide/plot_02_glm_demo.md index 162ae63f..592bba96 100644 --- a/docs/how_to_guide/plot_02_glm_demo.md +++ b/docs/how_to_guide/plot_02_glm_demo.md @@ -18,11 +18,12 @@ kernelspec: # GLM Demo: Toy Model Examples -!!! warning - This demonstration is currently in its alpha stage. It presents various regularization techniques on - GLMs trained on a Gaussian noise stimuli, and a minimal example of fitting and simulating a pair of coupled - neurons. More work needs to be done to properly compare the performance of the regularization strategies on - realistic simulations and real neural recordings. +:::{warning} +This demonstration is currently in its alpha stage. It presents various regularization techniques on +GLMs trained on a Gaussian noise stimuli, and a minimal example of fitting and simulating a pair of coupled +neurons. More work needs to be done to properly compare the performance of the regularization strategies on +realistic simulations and real neural recordings. +::: ## Introduction @@ -68,16 +69,16 @@ spikes = np.random.poisson(rate) ## The Feed-Forward GLM ### Model Definition -The class implementing the feed-forward GLM is `nemos.glm.GLM`. +The class implementing the feed-forward GLM is [`nemos.glm.GLM`](nemos.glm.GLM). In order to define the class, one **must** provide: - **Observation Model**: The observation model for the GLM, e.g. an object of the class of type -`nemos.observation_models.Observations`. So far, only the `PoissonObservations` +[`nemos.observation_models.Observations`](nemos.observation_models.Observations). So far, only the [`PoissonObservations`](nemos.observation_models.PoissonObservations) model has been implemented. -- **Regularizer**: The desired regularizer, e.g. an object of the `nemos.regularizer.Regularizer` class. +- **Regularizer**: The desired regularizer, e.g. an object of the [`nemos.regularizer.Regularizer`](nemos.regularizer.Regularizer) class. Currently, we implemented the un-regularized, Ridge, Lasso, and Group-Lasso regularization. -The default for the GLM class is the `PoissonObservations` with log-link function with a Ridge regularization. +The default for the GLM class is the [`PoissonObservations`](nemos.observation_models.PoissonObservations) with log-link function with a Ridge regularization. Here is how to define the model. @@ -90,7 +91,7 @@ print("Observation model:", type(model.observation_model)) ``` ### Model Configuration -One could visualize the model hyperparameters by calling `get_params` method. +One could visualize the model hyperparameters by calling [`get_params`](nemos.glm.GLM.get_params) method. ```{code-cell} ipython3 @@ -128,7 +129,7 @@ print("Regularizer type: ", type(model.regularizer)) print("Observation model:", type(model.observation_model)) ``` -Hyperparameters can be set at any moment via the `set_params` method. +Hyperparameters can be set at any moment via the [`set_params`](nemos.glm.GLM.set_params) method. ```{code-cell} ipython3 @@ -141,14 +142,14 @@ print("Updated regularizer: ", model.regularizer) print("Updated NL: ", model.observation_model.inverse_link_function) ``` -!!! warning - Each `Regularizer` has an associated attribute `Regularizer.allowed_solvers` - which lists the optimizers that are suited for each optimization problem. - For example, a `Ridge` is differentiable and can be fit with `GradientDescent` - , `BFGS`, etc., while a `Lasso` should use the `ProximalGradient` method instead. - If the provided `solver_name` is not listed in the `allowed_solvers` this will raise an - exception. - +:::{warning} +Each [`Regularizer`](regularizers) has an associated attribute [`Regularizer.allowed_solvers`](nemos.regularizer.Regularizer.allowed_solvers) +which lists the optimizers that are suited for each optimization problem. +For example, a [`Ridge`](nemos.regularizer.Ridge) is differentiable and can be fit with `GradientDescent` +, `BFGS`, etc., while a [`Lasso`](nemos.regularizer.Lasso) should use the `ProximalGradient` method instead. +If the provided `solver_name` is not listed in the `allowed_solvers` this will raise an +exception. +::: +++ diff --git a/docs/how_to_guide/plot_03_glm_pytree.md b/docs/how_to_guide/plot_03_glm_pytree.md deleted file mode 100644 index ea36b4b4..00000000 --- a/docs/how_to_guide/plot_03_glm_pytree.md +++ /dev/null @@ -1,354 +0,0 @@ ---- -jupytext: - text_representation: - extension: .md - format_name: myst - format_version: 0.13 - jupytext_version: 1.16.4 -kernelspec: - display_name: Python 3 - language: python - name: python3 ---- - -```{code-cell} ipython3 -%matplotlib inline -``` - -# FeaturePytree example - -This small example notebook shows how to use our custom FeaturePytree objects -instead of arrays to represent the design matrix. It will show that these two -representations are equivalent. - -This demo will fit the Poisson-GLM to some synthetic data. We will first show -the simple case, with a single neuron receiving some input. We will then show a -two-neuron system, to demonstrate how FeaturePytree can make it easier to -separate examine separate types of inputs. - -First, however, let's briefly discuss FeaturePytrees. - -```{code-cell} ipython3 -import jax -import jax.numpy as jnp -import numpy as np - -import nemos as nmo - -np.random.seed(111) -``` - -## FeaturePytrees - -A FeaturePytree is a custom NeMoS object used to represent design matrices, -GLM coefficients, and other similar variables. It is a simple -[pytree](https://jax.readthedocs.io/en/latest/pytrees.html), a dictionary -with strings as keys and arrays as values. These arrays must all have the -same number of elements along the first dimension, which represents the time -points, but can have different numbers of elements along the other dimensions -(and even different numbers of dimensions). - - -```{code-cell} ipython3 -example_pytree = nmo.pytrees.FeaturePytree(feature_0=np.random.normal(size=(100, 1, 2)), - feature_1=np.random.normal(size=(100, 2)), - feature_2=np.random.normal(size=(100, 5))) -example_pytree -``` - -FeaturePytrees can be indexed into like dictionary, so we can grab a -single one of their features: - - -```{code-cell} ipython3 -example_pytree['feature_0'].shape -``` - -We can grab the number of time points by getting the length or using the -`shape` attribute - - -```{code-cell} ipython3 -print(len(example_pytree)) -print(example_pytree.shape) -``` - -We can also jointly index into the FeaturePytree's leaves: - - -```{code-cell} ipython3 -example_pytree[:10] -``` - -We can add new features after initialization, as long as they have the same -number of time points. - - -```{code-cell} ipython3 -example_pytree['feature_3'] = np.zeros((100, 2, 4)) -``` - -However, if we try to add a new feature with the wrong number of time points, -we'll get an exception: - - -```{code-cell} ipython3 -try: - example_pytree['feature_4'] = np.zeros((99, 2, 4)) -except ValueError as e: - print(e) -``` - -Similarly, if we try to add a feature that's not an array: - - -```{code-cell} ipython3 -try: - example_pytree['feature_4'] = "Strings are very predictive" -except ValueError as e: - print(e) -``` - -FeaturePytrees are intended to be used with -[jax.tree_util.tree_map](https://jax.readthedocs.io/en/latest/_autosummary/jax.tree_util.tree_map.html), -a useful function for performing computations on arbitrary pytrees, -preserving their structure. - - -+++ - -We can map lambda functions: - - -```{code-cell} ipython3 -mapped = jax.tree_util.tree_map(lambda x: x**2, example_pytree) -print(mapped) -mapped['feature_1'] -``` - -Or functions from jax or numpy that operate on arrays: - - -```{code-cell} ipython3 -mapped = jax.tree_util.tree_map(jnp.exp, example_pytree) -print(mapped) -mapped['feature_1'] -``` - -We can change the dimensionality of our pytree: - - -```{code-cell} ipython3 -mapped = jax.tree_util.tree_map(lambda x: jnp.mean(x, axis=-1), example_pytree) -print(mapped) -mapped['feature_1'] -``` - -Or the number of time points: - - -```{code-cell} ipython3 -mapped = jax.tree_util.tree_map(lambda x: x[::10], example_pytree) -print(mapped) -mapped['feature_1'] -``` - -If we map something whose output cannot be a FeaturePytree (because its -values are scalars or non-arrays), we return a dictionary of arrays instead: - - -```{code-cell} ipython3 -print(jax.tree_util.tree_map(jnp.mean, example_pytree)) -print(jax.tree_util.tree_map(lambda x: x.shape, example_pytree)) -import matplotlib.pyplot as plt -import pynapple as nap -``` - -## FeaturePytrees and GLM - -These properties make FeaturePytrees useful for representing design matrices -and similar objects for the GLM. - -First, let's get our dataset and do some initial exploration of it. To do so, -we'll use pynapple to [stream -data](https://pynapple.org/examples/tutorial_pynapple_dandi.html) -from the DANDI archive. - -!!! attention - - We need some additional packages for this portion, which you can install - with `pip install dandi pynapple` - - -```{code-cell} ipython3 -io = nmo.fetch.download_dandi_data( - "000582", - "sub-11265/sub-11265_ses-07020602_behavior+ecephys.nwb", -) - -nwb = nap.NWBFile(io.read(), lazy_loading=False) - -print(nwb) -``` - -This data set has cells that are tuned for head direction and 2d position. -Let's compute some simple tuning curves to see if we can find a cell that -looks tuned for both. - - -```{code-cell} ipython3 -tc, binsxy = nap.compute_2d_tuning_curves(nwb['units'], nwb['SpatialSeriesLED1'].dropna(), 20) -fig, axes = plt.subplots(3, 3, figsize=(9, 9)) -for i, ax in zip(tc.keys(), axes.flatten()): - ax.imshow(tc[i], origin="lower", aspect="auto") - ax.set_title("Unit {}".format(i)) -axes[-1,-1].remove() -plt.tight_layout() - -# compute head direction. -diff = nwb['SpatialSeriesLED1'].values-nwb['SpatialSeriesLED2'].values -head_dir = np.arctan2(*diff.T) -head_dir = nap.Tsd(nwb['SpatialSeriesLED1'].index, head_dir) - -tune_head = nap.compute_1d_tuning_curves(nwb['units'], head_dir.dropna(), 30) - -fig, axes = plt.subplots(3, 3, figsize=(9, 9), subplot_kw={'projection': 'polar'}) -for i, ax in zip(tune_head.columns, axes.flatten()): - ax.plot(tune_head.index, tune_head[i]) - ax.set_title("Unit {}".format(i)) -axes[-1,-1].remove() -``` - -Okay, let's use unit number 7. - -Now let's set up our design matrix. First, let's fit the head direction by -itself. Head direction is a circular variable (pi and -pi are adjacent to -each other), so we need to use a basis that has this property as well. -`CyclicBSplineBasis` is one such basis. - -Let's create our basis and then arrange our data properly. - - -```{code-cell} ipython3 -unit_no = 7 -spikes = nwb['units'][unit_no] - -basis = nmo.basis.CyclicBSplineBasis(10, order=5) -x = np.linspace(-np.pi, np.pi, 100) -plt.figure() -plt.plot(x, basis(x)) - -# Find the interval on which head_dir has no NaNs -head_dir = head_dir.dropna() -# Grab the second (of two), since the first one is really short -valid_data= head_dir.time_support.loc[[1]] -head_dir = head_dir.restrict(valid_data) -# Count spikes at the same rate as head direction, over the same epoch -spikes = spikes.count(bin_size=1/head_dir.rate, ep=valid_data) -# the time points for spike are in the middle of these bins (whereas for -# head_dir they're at the ends), so use interpolate to shift head_dir to the -# center. -head_dir = head_dir.interpolate(spikes) - -X = nmo.pytrees.FeaturePytree(head_direction=basis(head_dir)) -``` - -Now we'll fit our GLM and then see what our head direction tuning looks like: - - -```{code-cell} ipython3 -model = nmo.glm.GLM(regularizer="Ridge", regularizer_strength=0.001) -model.fit(X, spikes) -print(model.coef_['head_direction']) - -bs_vis = basis(x) -tuning = jnp.einsum('b, tb->t', model.coef_['head_direction'], bs_vis) -plt.figure() -plt.polar(x, tuning) -``` - -This looks like a smoothed version of our tuning curve, like we'd expect! - -For a more direct comparison, we can plot the tuning function based on the model predicted -firing rates with that estimated from the counts. - - -```{code-cell} ipython3 -# predict rates and convert back to pynapple -rates_nap = nap.TsdFrame(t=head_dir.t, d=np.asarray(model.predict(X))) -# compute tuning function -tune_head_model = nap.compute_1d_tuning_curves_continuous(rates_nap, head_dir, 30) -# compare model prediction with data -fig, ax = plt.subplots(1, 1, subplot_kw={'projection': 'polar'}) -ax.plot(tune_head[7], label="counts") -# multiply by the sampling rate for converting to spike/sec. -ax.plot(tune_head_model * rates_nap.rate, label="model") - -# Let's compare this to using arrays, to see what it looks like: - -model = nmo.glm.GLM() -model.fit(X['head_direction'], spikes) -model.coef_ -``` - -We can see that the solution is identical, as is the way of interacting with -the GLM object. - -However, with a single type of feature, it's unclear why exactly this is -helpful. Let's add a feature for the animal's position in space. For this -feature, we need a 2d basis. Let's use some raised cosine bumps and organize -our data similarly. - - -```{code-cell} ipython3 -pos_basis = nmo.basis.RaisedCosineBasisLinear(10) * nmo.basis.RaisedCosineBasisLinear(10) -spatial_pos = nwb['SpatialSeriesLED1'].restrict(valid_data) - -X['spatial_position'] = pos_basis(*spatial_pos.values.T) -``` - -Running the GLM is identical to before, but we can see that our coef_ -FeaturePytree now has two separate keys, one for each feature type. - - -```{code-cell} ipython3 -model = nmo.glm.GLM(solver_name="LBFGS") -model.fit(X, spikes) -model.coef_ -``` - -Let's visualize our tuning. Head direction looks pretty much the same (though -the values are slightly different, as we can see when printing out the -coefficients). - - -```{code-cell} ipython3 -bs_vis = basis(x) -tuning = jnp.einsum('b,nb->n', model.coef_['head_direction'], bs_vis) -print(model.coef_['head_direction']) -plt.figure() -plt.polar(x, tuning.T) -``` - -And the spatial tuning again looks like a smoothed version of our earlier -tuning curves. - - -```{code-cell} ipython3 -_, _, pos_bs_vis = pos_basis.evaluate_on_grid(50, 50) -pos_tuning = jnp.einsum('b,ijb->ij', model.coef_['spatial_position'], pos_bs_vis) -plt.figure() -plt.imshow(pos_tuning) -``` - -We could do all this with matrices as well, but we have to pay attention to -indices in a way that is annoying: - - -```{code-cell} ipython3 -X_mat = nmo.utils.pynapple_concatenate_jax([X['head_direction'], X['spatial_position']], -1) - -model = nmo.glm.GLM() -model.fit(X_mat, spikes) -model.coef_[..., :basis.n_basis_funcs] -``` diff --git a/docs/how_to_guide/plot_04_population_glm.md b/docs/how_to_guide/plot_04_population_glm.md deleted file mode 100644 index 2a74ce93..00000000 --- a/docs/how_to_guide/plot_04_population_glm.md +++ /dev/null @@ -1,219 +0,0 @@ ---- -jupytext: - text_representation: - extension: .md - format_name: myst - format_version: 0.13 - jupytext_version: 1.16.4 -kernelspec: - display_name: Python 3 - language: python - name: python3 ---- - -```{code-cell} ipython3 -%matplotlib inline -``` - - -# Population GLM - -Fitting the activity of a neural population with NeMoS can be much more efficient than fitting each individual -neuron in a loop. The reason for this is that NeMoS leverages the powerful GPU-vectorization implemented by `JAX`. - - -!!! note - For an unregularized, Lasso, Ridge, or group-Lasso GLM, fitting a GLM one neuron at the time, or fitting jointly - the neural population is equivalent. The main difference between the approaches is that the former is more - memory efficient, the latter is computationally more efficient (it takes less time to fit). - -## Fitting a Population GLM - -NeMoS has a dedicated `nemos.GLM.PopulationGLM` class for fitting jointly a neural population. The API - is very similar to that the regular `nemos.glm.GLM`, but with a few differences: - - 1. The `y` input to the methods `fit` and `score` must be a two-dimensional array of shape `(n_samples, n_neurons)`. - 2. You can optionally pass a `feature_mask` in the form of an array of 0s and 1s with shape `(n_features, n_neurons)` - that specifies which features are used as predictors for each neuron. More on this [later](#neuron-specific-features). - -Let's generate some synthetic data and fit a population model. - -```{code-cell} ipython3 -import jax.numpy as jnp -import matplotlib.pyplot as plt -import numpy as np - -import nemos as nmo - -np.random.seed(123) - -n_features = 5 -n_neurons = 2 -n_samples = 500 - -# random design array. Shape (n_time_points, n_features). -X = 0.5*np.random.normal(size=(n_samples, n_features)) - -# log-rates & weights -b_true = np.zeros((n_neurons, )) -w_true = np.random.uniform(size=(n_features, n_neurons)) - - -# generate counts (spikes will be (n_samples, n_features) -rate = jnp.exp(jnp.dot(X, w_true) + b_true) -spikes = np.random.poisson(rate) - -print(spikes.shape) -``` - -We can now instantiate the `PopulationGLM` model and fit. - - -```{code-cell} ipython3 -model = nmo.glm.PopulationGLM() -model.fit(X, spikes) - -print(f"population GLM log-likelihood: {model.score(X, spikes)}") -``` - -## Neuron-specific features -If you want to model neurons with different input features, the way to do so is to specify a `feature_mask`. -Let's assume that we have two neurons, share one shared input, and have an extra private one, for a total of -3 inputs. - - -```{code-cell} ipython3 -# let's take the first three input -n_features = 3 -input_features = X[:, :3] -``` - -Let's assume that: - - - `input_features[:, 0]` is shared. - - `input_features[:, 1]` is an input only for the first neuron. - - `input_features[:, 2]` is an input only for the second neuron. - -We can simulate this scenario, - - -```{code-cell} ipython3 -# model the rate of the first neuron using only the first two features and weights. -rate_neuron_1 = jnp.exp(np.dot(input_features[:, [0, 1]], w_true[: 2, 0])) - -# model the rate of the second neuron using only the first and last feature and weights. -rate_neuron_2 = jnp.exp(np.dot(input_features[:, [0, 2]], w_true[[0, 2], 1])) - -# stack the rates in a (n_samples, n_neurons) array and generate spikes -rate = np.hstack((rate_neuron_1[:, np.newaxis], rate_neuron_2[:, np.newaxis])) -spikes = np.random.poisson(rate) -``` - -We can impose the same constraint to the `PopulationGLM` by masking the weights. - - -```{code-cell} ipython3 -# initialize the mask to a matrix of 1s. -feature_mask = np.ones((n_features, n_neurons)) - -# remove the 3rd feature from the predictors of the first neuron -feature_mask[2, 0] = 0 - -# remove the 2nd feature from the predictors of the second neuron -feature_mask[1, 1] = 0 - -# visualize the mask -print(feature_mask) -``` - -The mask can be passed at initialization or set after the model is initialized, but cannot be changed -after the model is fit. - - -```{code-cell} ipython3 -# set a quasi-newton solver and low tolerance for better numerical precision -model = nmo.glm.PopulationGLM(solver_name="LBFGS", solver_kwargs={"tol": 10**-12}) - -# set the mask -model.feature_mask = feature_mask - -# fit the model -model.fit(input_features, spikes) -``` - -If we print the model coefficients, we can see the effect of the mask. - - -```{code-cell} ipython3 -print(model.coef_) -``` - -The coefficient for the first neuron corresponding to the last feature is zero, as well as -the coefficient of the second neuron corresponding to the second feature. - -To convince ourselves that this is equivalent to fit each neuron individually with the correct features, -let's go ahead and try. - - -```{code-cell} ipython3 -# features for each neuron -features_by_neuron = { - 0: [0, 1], - 1: [0, 2] -} -# initialize the coefficients -coeff = np.zeros((2, 2)) - -# loop over the neurons and fit a GLM -for neuron in range(2): - model_neu = nmo.glm.GLM( - solver_name="LBFGS", solver_kwargs={"tol":10**-12} - ) - model_neu.fit(input_features[:, features_by_neuron[neuron]], spikes[:, neuron]) - coeff[:, neuron] = model_neu.coef_ - -# visually compare the estimated coeffeicients -fig, axs = plt.subplots(1, 2, figsize=(6, 3)) -for neuron in range(2): - axs[neuron].set_title(f"neuron {neuron}") - axs[neuron].bar([0, 4], w_true[features_by_neuron[neuron], neuron], width=0.8, label="true") - axs[neuron].bar([1, 5], coeff[:, neuron], width=0.8, label="single neuron GLM") - axs[neuron].bar([2, 6], model.coef_[features_by_neuron[neuron], neuron], width=0.8, label="population GLM") - axs[neuron].set_ylabel("coefficient") - axs[neuron].set_ylim(0, 0.8) - axs[neuron].set_xticks([0.5, 3.5]) - axs[neuron].set_xticklabels(["feature 0", f"feature {neuron + 1}"]) - if neuron == 1: - plt.legend() -plt.tight_layout() -``` - -## FeaturePytree -`PopulationGLM` is compatible with [`FeaturePytree`](../plot_03_glm_pytree). If you structured your predictors -in a `FeaturePytree`, the `feature_mask` needs to be a dictionary of the same structure, containing arrays -of shape `(n_neurons, )`. -The example above can be reformulated as follows, - - -```{code-cell} ipython3 -# restructure the input as FeaturePytree -pytree_features = nmo.pytrees.FeaturePytree( - shared=input_features[:, :1], - neu_0=input_features[:, 1:2], - neu_1=input_features[:, 2:] -) - -# Define a mask as a dictionary -pytree_mask = dict( - shared=np.array([1, 1]), - neu_0=np.array([1, 0]), - neu_1=np.array([0, 1]) -) - -# fit a model -model_tree = nmo.glm.PopulationGLM(solver_name="LBFGS", feature_mask=pytree_mask) -model_tree.fit(pytree_features, spikes) - -# print the coefficients -print(model_tree.coef_) -``` diff --git a/docs/how_to_guide/plot_05_batch_glm.md b/docs/how_to_guide/plot_05_batch_glm.md deleted file mode 100644 index ef7566c0..00000000 --- a/docs/how_to_guide/plot_05_batch_glm.md +++ /dev/null @@ -1,243 +0,0 @@ ---- -jupytext: - text_representation: - extension: .md - format_name: myst - format_version: 0.13 - jupytext_version: 1.16.4 -kernelspec: - display_name: Python 3 - language: python - name: python3 ---- - -```{code-cell} ipython3 -%matplotlib inline -``` - - -# Batching example - -Here we demonstrate how to setup and run a stochastic gradient descent in `nemos` -by batching and using the `update` method of the model class. - -```{code-cell} ipython3 -import matplotlib.pyplot as plt -import numpy as np -import pynapple as nap - -import nemos as nmo - -nap.nap_config.suppress_conversion_warnings = True - -# set random seed -np.random.seed(123) -``` - -## Simulate data - -Let's generate some data artificially - - -```{code-cell} ipython3 -n_neurons = 10 -T = 50 - -times = np.linspace(0, T, 5000).reshape(-1, 1) -rate = np.exp(np.sin(times + np.linspace(0, np.pi*2, n_neurons).reshape(1, n_neurons))) -``` - -Get the spike times from the rate and generate a `TsGroup` object - - -```{code-cell} ipython3 -spike_t, spike_id = np.where(np.random.poisson(rate)) -units = nap.Tsd(spike_t/T, spike_id).to_tsgroup() -``` - -## Model configuration - -Let's imagine this dataset do not fit in memory. We can use a batching approach to train the GLM. -First we need to instantiate the `PopulationGLM`. The default algorithm for `PopulationGLM` is gradient descent. -We suggest to use it for batching. - -!!! Note - You must shutdown the dynamic update of the step for fitting a batched (also called stochastic) gradient descent. - In jaxopt, this can be done by setting the parameters `acceleration` to False and setting the `stepsize`. - - - -```{code-cell} ipython3 -glm = nmo.glm.PopulationGLM( - solver_name="GradientDescent", - solver_kwargs={"stepsize": 0.1, "acceleration": False} - ) -``` - -## Basis instantiation - -Here we instantiate the basis. `ws` is 40 time bins. It corresponds to a 200 ms windows - - -```{code-cell} ipython3 -ws = 40 -basis = nmo.basis.RaisedCosineBasisLog(5, mode="conv", window_size=ws) -``` - -## Batch definition - -The batch size needs to be larger than the window size of the convolution kernel defined above. - - -```{code-cell} ipython3 -batch_size = 5 # second -``` - -Here we define a batcher function that generate a random 5 s of design matrix and spike counts. -This function will be called during each iteration of the stochastic gradient descent. - - -```{code-cell} ipython3 -def batcher(): - # Grab a random time within the time support. Here is the time support is one epoch only so it's easy. - t = np.random.uniform(units.time_support[0, 0], units.time_support[0, 1]-batch_size) - - # Bin the spike train in a 1s batch - ep = nap.IntervalSet(t, t+batch_size) - counts = units.restrict(ep).count(0.005) # count in 5 ms bins - - # Convolve - X = basis.compute_features(counts) - - # Return X and counts - return X, counts -``` - -## Solver initialization - -First we need to initialize the gradient descent solver within the `PopulationGLM`. -This gets you the initial parameters and the first state of the solver. - - -```{code-cell} ipython3 -params = glm.initialize_params(*batcher()) -state = glm.initialize_state(*batcher(), params) -``` - -## Batch learning - -Let's do a few iterations of gradient descent calling the `batcher` function at every step. -At each step, we store the log-likelihood of the model for each neuron evaluated on the batch - - -```{code-cell} ipython3 -n_step = 500 -logl = np.zeros(n_step) - -for i in range(n_step): - - # Get a batch of data - X, Y = batcher() - - # Do one step of gradient descent. - params, state = glm.update(params, state, X, Y) - - # Score the model along the time axis - logl[i] = glm.score(X, Y, score_type="log-likelihood") -``` - -!!! Warning "Input validation" - The `update` method does not perform input validation each time it is called. - This design choice speeds up computation by avoiding repetitive checks. However, - it requires that all inputs to the `update` method strictly conform to the expected - dimensionality and structure as established during the initialization of the solver. - Failure to comply with these expectations will likely result in runtime errors or - incorrect computations. - -First let's plot the log-likelihood to see if the model is converging. - - -```{code-cell} ipython3 -plt.figure() -plt.plot(logl) -plt.xlabel("Iteration") -plt.ylabel("Log-likelihood") -plt.show() -``` - -We can see that the log-likelihood is increasing but did not reach plateau yet. -The number of iterations can be increased to continue learning. - -We can take a look at the coefficients. -Here we extract the weight matrix of shape `(n_neurons*n_basis, n_neurons)` -and reshape it to `(n_neurons, n_basis, n_neurons)`. -We then average along basis to get a weight matrix of shape `(n_neurons, n_neurons)`. - - -```{code-cell} ipython3 -W = glm.coef_.reshape(len(units), basis.n_basis_funcs, len(units)) -Wm = np.mean(np.abs(W), 1) - -# Let's plot it. - -plt.figure() -plt.imshow(Wm) -plt.xlabel("Neurons") -plt.ylabel("Neurons") -plt.show() -``` - -## Model comparison - -Since this example is small enough, we can fit the full model and compare the scores. -Here we generate the design matrix and spike counts for the whole dataset. - - -```{code-cell} ipython3 -Y = units.count(0.005) -X = basis.compute_features(Y) -full_model = nmo.glm.PopulationGLM().fit(X, Y) -``` - -Now that the full model is fitted, we are scoring the full model and the batch model against the full datasets to compare the scores. -The score is pseudo-R2 - - -```{code-cell} ipython3 -full_scores = full_model.score( - X, Y, aggregate_sample_scores=lambda x:np.mean(x, axis=0), score_type="pseudo-r2-McFadden" -) -batch_scores = glm.score( - X, Y, aggregate_sample_scores=lambda x:np.mean(x, axis=0), score_type="pseudo-r2-McFadden" -) -``` - -Let's compare scores for each neurons as well as the coefficients. - - -```{code-cell} ipython3 -plt.figure(figsize=(10, 8)) -gs = plt.GridSpec(3,2) -plt.subplot(gs[0,:]) -plt.bar(np.arange(0, n_neurons), full_scores, 0.4, label="Full model") -plt.bar(np.arange(0, n_neurons)+0.5, batch_scores, 0.4, label="Batch model") -plt.ylabel("Pseudo R2") -plt.xlabel("Neurons") -plt.ylim(0, 1) -plt.legend() -plt.subplot(gs[1:,0]) -plt.imshow(Wm) -plt.title("Batch model") -plt.subplot(gs[1:,1]) -Wm2 = np.mean( - np.abs( - full_model.coef_.reshape(len(units), basis.n_basis_funcs, len(units)) - ) - , 1) -plt.imshow(Wm2) -plt.title("Full model") -plt.tight_layout() -plt.show() -``` - -As we can see, with a few iterations, the batch model manage to recover a similar coefficient matrix. diff --git a/docs/how_to_guide/plot_06_sklearn_pipeline_cv_demo.md b/docs/how_to_guide/plot_06_sklearn_pipeline_cv_demo.md deleted file mode 100644 index 35ff196a..00000000 --- a/docs/how_to_guide/plot_06_sklearn_pipeline_cv_demo.md +++ /dev/null @@ -1,552 +0,0 @@ ---- -jupytext: - text_representation: - extension: .md - format_name: myst - format_version: 0.13 - jupytext_version: 1.16.4 -kernelspec: - display_name: Python 3 - language: python - name: python3 ---- - -```{code-cell} ipython3 -%matplotlib inline -``` - - -# Selecting basis by cross-validation with scikit-learn - -In this demo, we will demonstrate how to select an appropriate basis and its hyperparameters using cross-validation. -In particular, we will learn: - -1. What a scikit-learn pipeline is. -2. Why pipelines are useful. -3. How to combine NeMoS `Basis` and `GLM` objects in a pipeline. -4. How to select the number of bases and the basis type through cross-validation (or any other hyperparameter in the pipeline). -5. How to use a custom scoring metric to quantify the performance of each configuration. - -+++ - -## What is a scikit-learn pipeline - -
-Pipeline illustration. -
Schematic of a scikit-learn pipeline.
-
- -A pipeline is a sequence of data transformations leading up to a model. Each step before the final one transforms the input data into a different representation, and then the final model step fits, predicts, or scores based on the previous step's output and some observations. Setting up such machinery can be simplified using the `Pipeline` class from scikit-learn. - -To set up a scikit-learn `Pipeline`, ensure that: - -1. Each intermediate step is a [scikit-learn transformer object](https://scikit-learn.org/stable/data_transforms.html) with a `transform` and/or `fit_transform` method. -2. The final step is an [estimator object](https://scikit-learn.org/stable/developers/develop.html#estimators) with a `fit` method, or a model with `fit`, `predict`, and `score` methods. - -Each transformation step takes a 2D array `X` of shape `(num_samples, num_original_features)` as input and outputs another 2D array of shape `(num_samples, num_transformed_features)`. The final step takes a pair `(X, y)`, where `X` is as before, and `y` is a 1D array of shape `(n_samples,)` containing the observations to be modeled. - -You can define a pipeline as follows: -```python -from sklearn.pipeline import Pipeline - -# Assume transformer_i/predictor is a transformer/model object -pipe = Pipeline( - [ - ("label_1", transformer_1), - ("label_2", transformer_2), - ..., - ("label_n", transformer_n), - ("label_model", model) - ] -) -``` - -Note that you have to assign a label to each step of the pipeline. -!!! tip - Here we used a placeholder `"label_i"` for demonstration; you should choose a more descriptive name depending on the type of transformation step. - -Calling `pipe.fit(X, y)` will perform the following computations: -```python -# Chain of transformations -X1 = transformer_1.fit_transform(X) -X2 = transformer_2.fit_transform(X1) -# ... -Xn = transformer_n.fit_transform(Xn_1) - -# Fit step -model.fit(Xn, y) -``` -And the same holds for `pipe.score` and `pipe.predict`. - -## Why pipelines are useful - -Pipelines not only streamline and simplify your code but also offer several other advantages. The real power of pipelines becomes evident when combined with the scikit-learn `model_selection` module, which includes cross-validation and similar methods. This combination allows you to tune hyperparameters at each step of the pipeline in a straightforward manner. - -In the following sections, we will showcase this approach with a concrete example: selecting the appropriate basis type and number of bases for a GLM regression in NeMoS. - -## Combining basis transformations and GLM in a pipeline -Let's start by creating some toy data. - - -```{code-cell} ipython3 -import matplotlib.pyplot as plt -import numpy as np -import pandas as pd -import scipy.stats -import seaborn as sns -from sklearn.model_selection import GridSearchCV -from sklearn.pipeline import Pipeline - -import nemos as nmo - -# some helper plotting functions -from nemos import _documentation_utils as doc_plots - -# predictors, shape (n_samples, n_features) -X = np.random.uniform(low=0, high=1, size=(1000, 1)) -# observed counts, shape (n_samples,) -rate = 2 * ( - scipy.stats.norm.pdf(X, scale=0.1, loc=0.25) - + scipy.stats.norm.pdf(X, scale=0.1, loc=0.75) -) -y = np.random.poisson(rate).astype(float).flatten() -``` - -Let's now plot the simulated neuron's tuning curve, which is bimodal, Gaussian-shaped, and has peaks at 0.25 and 0.75. - - -```{code-cell} ipython3 -fig, ax = plt.subplots() -ax.scatter(X.flatten(), y, alpha=0.2) -ax.set_xlabel("input") -ax.set_ylabel("spike count") -sns.despine(ax=ax) -``` - -### Converting NeMoS `Basis` to a transformer -In order to use NeMoS `Basis` in a pipeline, we need to convert it into a scikit-learn transformer. This can be achieved through the `TransformerBasis` wrapper class. - -Instantiating a `TransformerBasis` can be done either using the constructor directly or with `Basis.to_transformer()`: - - -```{code-cell} ipython3 -bas = nmo.basis.RaisedCosineBasisLinear(5, mode="conv", window_size=5) -# these two ways of creating the TransformerBasis are equivalent -trans_bas_a = nmo.basis.TransformerBasis(bas) -trans_bas_b = bas.to_transformer() -``` - -`TransformerBasis` provides convenient access to the underlying `Basis` object's attributes: - - -```{code-cell} ipython3 -print(bas.n_basis_funcs, trans_bas_a.n_basis_funcs, trans_bas_b.n_basis_funcs) -``` - -We can also set attributes of the underlying `Basis`. Note that -- because `TransformerBasis` is created with a copy of the `Basis` object passed to it -- this does not change the original `Basis`, and neither does changing the original `Basis` change `TransformerBasis` we created: - - -```{code-cell} ipython3 -trans_bas_a.n_basis_funcs = 10 -bas.n_basis_funcs = 100 - -print(bas.n_basis_funcs, trans_bas_a.n_basis_funcs, trans_bas_b.n_basis_funcs) -``` - -### Creating and fitting a pipeline -We might want to combine first transforming the input data with our basis functions, then fitting a GLM on the transformed data. - -This is exactly what `Pipeline` is for! - - -```{code-cell} ipython3 -pipeline = Pipeline( - [ - ( - "transformerbasis", - nmo.basis.TransformerBasis(nmo.basis.RaisedCosineBasisLinear(6)), - ), - ( - "glm", - nmo.glm.GLM(regularizer_strength=0.5, regularizer="Ridge"), - ), - ] -) - -pipeline.fit(X, y) -``` - -Note how NeMoS models are already scikit-learn compatible and can be used directly in the pipeline. - -Visualize the fit: - - -```{code-cell} ipython3 -# Predict the rate. -# Note that you need a 2D input even if x is a flat array. -# We are using expand dim to add the extra-dimension -x = np.sort(X, axis=0) -predicted_rate = pipeline.predict(x) -``` - -```{code-cell} ipython3 -fig, ax = plt.subplots() - -ax.scatter(X.flatten(), y, alpha=0.2, label="generated spike counts") -ax.set_xlabel("input") -ax.set_ylabel("spike count") - - -ax.plot( - x, - predicted_rate, - label="predicted rate", - color="tab:orange", -) - -ax.legend() -sns.despine(ax=ax) -``` - -The current model captures the bimodal distribution of responses, appropriately picking out the peaks. However, it doesn't do a good job capturing the actual firing rate: the peaks are too low and the valleys are not low enough. This might be because of our choice of basis and/or regularizer strength, so let's see if tuning those parameters results in a better fit! We could do this manually, but doing this with the sklearn pipeline will make everything much easier! - - -+++ - -### Select the number of basis by cross-validation - - -+++ - -!!! warning - Please keep in mind that while `GLM.score` supports different ways of evaluating goodness-of-fit through the `score_type` argument, `pipeline.score(X, y, score_type="...")` does not propagate this, and uses the default value of `log-likelihood`. - - To evaluate a pipeline, please create a custom scorer (e.g. `pseudo_r2` below) and call `my_custom_scorer(pipeline, X, y)`. - -#### Define the parameter grid - -Let's define candidate values for the parameters of each step of the pipeline we want to cross-validate. In this case the number of basis functions in the transformation step and the ridge regularization's strength in the GLM fit: - - -```{code-cell} ipython3 -param_grid = dict( - glm__regularizer_strength=(0.1, 0.01, 0.001, 1e-6), - transformerbasis__n_basis_funcs=(3, 5, 10, 20, 100), -) -``` - -!!! note "Grid definition" - In order to define a parameter grid dictionary for a pipeline, you must structure the dictionary keys as follows: - - - Start with the pipeline label (`"glm"` or `"transformerbasis"` for us). This determines which pipeline step has the relevant hyperparameter. - - Add `"__"` followed by the hyperparameter name (for example, `"n_basis_funcs"`). - - If the hyperparameter is itself an object with attributes, add another `"__"` followed by the attribute name. For instance, `"glm__observation_model__inverse_link_function"` - would be a valid key for cross-validating over the link function of the GLM's `observation_model` attribute `inverse_link_function`. - The values in the dictionary are the parameters to be tested. - - -+++ - -#### Run the grid search -Let's run a 5-fold cross-validation of the hyperparameters with the scikit-learn `model_selection.GridsearchCV` class. -??? info "K-Fold cross-validation" -

- Grid Search Cross Validation -
- K-fold cross-validation (modified from scikit-learn docs) -

- K-fold cross-validation is a robust method used for selecting hyperparameters. In this procedure, the data is divided into K equally sized chunks (or folds). The model is trained on K-1 of these chunks, with the remaining chunk used for evaluation. This process is repeated K times, with each chunk being used exactly once as the evaluation set. - After completing the K iterations, the K evaluation scores are averaged to provide a reliable estimate of the model's performance. To select the optimal hyperparameters, K-fold cross-validation can be applied over a grid of potential hyperparameters, with the set yielding the highest average score being chosen as the best. - - -```{code-cell} ipython3 -gridsearch = GridSearchCV( - pipeline, - param_grid=param_grid, - cv=5 -) - -# run the 5-fold cross-validation grid search -gridsearch.fit(X, y) -``` - -??? note "Manual cross-validation" - To appreciate how much boiler-plate code we are saving by calling scikit-learn cross-validation, below - we can see how this cross-validation will look like in a manual loop. - - ```python - from itertools import product - from copy import deepcopy - - regularizer_strength = (0.1, 0.01, 0.001, 1e-6) - n_basis_funcs = (3, 5, 10, 20, 100) - - # define the folds - n_folds = 5 - fold_idx = np.arange(X.shape[0] - X.shape[0] % n_folds).reshape(n_folds, -1) - - - # Initialize the scores - scores = np.zeros((len(regularizer_strength) * len(n_basis_funcs), n_folds)) - - # Dictionary to store coefficients - coeffs = {} - - # initialize basis and model - basis = nmo.basis.TransformerBasis(nmo.basis.RaisedCosineBasisLinear(6)) - model = nmo.glm.GLM(regularizer="Ridge") - - # loop over combinations - for fold in range(n_folds): - test_idx = fold_idx[fold] - train_idx = fold_idx[[x for x in range(n_folds) if x != fold]].flatten() - for i, params in enumerate(product(regularizer_strength, n_basis_funcs)): - reg_strength, n_basis = params - - # deepcopy the basis and model - bas = deepcopy(basis) - glm = deepcopy(model) - - # set the parameters - bas.n_basis_funcs = n_basis - glm.regularizer_strength = reg_strength - - # fit the model - glm.fit(bas.transform(X[train_idx]), y[train_idx]) - - # store score and coefficients - scores[i, fold] = glm.score(bas.transform(X[test_idx]), y[test_idx]) - coeffs[(i, fold)] = (glm.coef_, glm.intercept_) - - # get the best mean test score - i_best = np.argmax(scores.mean(axis=1)) - # get the overall best coeffs - fold_best = np.argmax(scores[i_best]) - - # set up the best model - model.coef_ = coeffs[(i_best, fold_best)][0] - model.intercept_ = coeffs[(i_best, fold_best)][1] - - # get the best hyperparameters - best_reg_strength = regularizer_strength[i_best // len(n_basis_funcs)] - best_n_basis = n_basis_funcs[i_best % len(n_basis_funcs)] - ``` - - -+++ - -#### Visualize the scores - -Let's extract the scores from `gridsearch` and take a look at how the different parameter values of our pipeline influence the test score: - - -```{code-cell} ipython3 -cvdf = pd.DataFrame(gridsearch.cv_results_) - -cvdf_wide = cvdf.pivot( - index="param_transformerbasis__n_basis_funcs", - columns="param_glm__regularizer_strength", - values="mean_test_score", -) - -doc_plots.plot_heatmap_cv_results(cvdf_wide) -``` - -The plot displays the model's log-likelihood for each parameter combination in the grid. The parameter combination with the highest score, which is the one selected by the procedure, is highlighted with a blue rectangle. We can thus see that we need 10 or more basis functions, and that all of the tested regularization strengths agree with each other. In general, we want the fewest number of basis functions required to get a good fit, so we'll choose 10 here. - -#### Visualize the predicted rate -Finally, visualize the predicted firing rates using the best model found by our grid-search, which gives a better fit than the randomly chosen parameter values we tried in the beginning: - - -```{code-cell} ipython3 -# Predict the ate using the best configuration, -x = np.sort(X, axis=0) -predicted_rate = gridsearch.best_estimator_.predict(x) -``` - -```{code-cell} ipython3 -fig, ax = plt.subplots() - -ax.scatter(X.flatten(), y, alpha=0.2, label="generated spike counts") -ax.set_xlabel("input") -ax.set_ylabel("spike count") - - -ax.plot( - x, - predicted_rate, - label="predicted rate", - color="tab:orange", -) - -ax.legend() -sns.despine(ax=ax) -``` - -:rocket::rocket::rocket: **Success!** :rocket::rocket::rocket: -We are now able to capture the distribution of the firing rate appropriately: both peaks and valleys in the spiking activity are matched by our model predicitons. - -### Evaluating different bases directly - -In the previous example we set the number of basis functions of the `Basis` wrapped in our `TransformerBasis`. However, if we are for example not sure about the type of basis functions we want to use, or we have already defined some basis functions of our own, then we can use cross-validation to directly evaluate those as well. - -Here we include `transformerbasis___basis` in the parameter grid to try different values for `TransformerBasis._basis`: - - -```{code-cell} ipython3 -param_grid = dict( - glm__regularizer_strength=(0.1, 0.01, 0.001, 1e-6), - transformerbasis___basis=( - nmo.basis.RaisedCosineBasisLinear(5), - nmo.basis.RaisedCosineBasisLinear(10), - nmo.basis.RaisedCosineBasisLog(5), - nmo.basis.RaisedCosineBasisLog(10), - nmo.basis.MSplineBasis(5), - nmo.basis.MSplineBasis(10), - ), -) -``` - -Then run the grid search: - - -```{code-cell} ipython3 -gridsearch = GridSearchCV( - pipeline, - param_grid=param_grid, - cv=5, -) - -# run the 5-fold cross-validation grid search -gridsearch.fit(X, y) -``` - -Wrangling the output data a bit and looking at the scores: - - -```{code-cell} ipython3 -cvdf = pd.DataFrame(gridsearch.cv_results_) - -# Read out the number of basis functions -cvdf["transformerbasis_config"] = [ - f"{b.__class__.__name__} - {b.n_basis_funcs}" - for b in cvdf["param_transformerbasis___basis"] -] - -cvdf_wide = cvdf.pivot( - index="transformerbasis_config", - columns="param_glm__regularizer_strength", - values="mean_test_score", -) - -doc_plots.plot_heatmap_cv_results(cvdf_wide) -``` - -As shown in the table, the model with the highest score, highlighted in blue, used a RaisedCosineBasisLinear basis (as used above), which appears to be a suitable choice for our toy data. -We can confirm that by plotting the firing rate predictions: - - -```{code-cell} ipython3 -# Predict the rate using the optimal configuration -x = np.sort(X, axis=0) -predicted_rate = gridsearch.best_estimator_.predict(x) -``` - -```{code-cell} ipython3 -fig, ax = plt.subplots() - -ax.scatter(X.flatten(), y, alpha=0.2, label="generated spike counts") -ax.set_xlabel("input") -ax.set_ylabel("spike count") - -ax.plot( - x, - predicted_rate, - label="predicted rate", - color="tab:orange", -) - -ax.legend() -sns.despine(ax=ax) -``` - -The plot confirms that the firing rate distribution is accurately captured by our model predictions. - - -+++ - -!!! warning - Please note that because it would lead to unexpected behavior, mixing the two ways of defining values for the parameter grid is not allowed. The following would lead to an error: - - ```python - param_grid = dict( - glm__regularizer_strength=(0.1, 0.01, 0.001, 1e-6), - transformerbasis__n_basis_funcs=(3, 5, 10, 20, 100), - transformerbasis___basis=( - nmo.basis.RaisedCosineBasisLinear(5), - nmo.basis.RaisedCosineBasisLinear(10), - nmo.basis.RaisedCosineBasisLog(5), - nmo.basis.RaisedCosineBasisLog(10), - nmo.basis.MSplineBasis(5), - nmo.basis.MSplineBasis(10), - ), - ) - ``` - - -+++ - -## Create a custom scorer -By default, the GLM score method returns the model log-likelihood. If you want to try a different metric, such as the pseudo-R2, you can create a custom scorer and pass it to the cross-validation object: - - -```{code-cell} ipython3 -from sklearn.metrics import make_scorer - -pseudo_r2 = make_scorer( - nmo.observation_models.PoissonObservations().pseudo_r2 -) -``` - -We can now run the grid search providing the custom scorer - - -```{code-cell} ipython3 -gridsearch = GridSearchCV( - pipeline, - param_grid=param_grid, - cv=5, - scoring=pseudo_r2, -) - -# Run the 5-fold cross-validation grid search -gridsearch.fit(X, y) -``` - -And finally, we can plot each model's score. - - -+++ - -Plot the pseudo-R2 scores - - -```{code-cell} ipython3 -cvdf = pd.DataFrame(gridsearch.cv_results_) - -# Read out the number of basis functions -cvdf["transformerbasis_config"] = [ - f"{b.__class__.__name__} - {b.n_basis_funcs}" - for b in cvdf["param_transformerbasis___basis"] -] - -cvdf_wide = cvdf.pivot( - index="transformerbasis_config", - columns="param_glm__regularizer_strength", - values="mean_test_score", -) - -doc_plots.plot_heatmap_cv_results(cvdf_wide, label="pseudo-R2") -``` - -As you can see, the results with pseudo-R2 agree with those of the negative log-likelihood. Note that this new metric is normalized between 0 and 1, with a higher score indicating better performance. diff --git a/docs/tutorials/README.md b/docs/tutorials/README.md index eef9ea5b..909f4364 100644 --- a/docs/tutorials/README.md +++ b/docs/tutorials/README.md @@ -2,9 +2,24 @@ A gallery of fully worked out tutorials analyzing neural recordings from different brain regions and recording modalities. -??? attention "Additional requirements" - To run the tutorials, you may need to install some additional packages used for plotting and data fetching. - You can install all of the required packages with the following command: - ``` - pip install nemos[examples] - ``` +:::{dropdown} "Additional requirements" +:color: warning +:icon: alert +To run the tutorials, you may need to install some additional packages used for plotting and data fetching. +You can install all of the required packages with the following command: +``` +pip install nemos[examples] +``` +::: + +```{toctree} +:maxdepth: 2 +:caption: Contents + +plot_01_current_injection.md +plot_02_head_direction.md +plot_03_grid_cells.md +plot_04_v1_cells.md +plot_05_place_cells.md +plot_06_calcium_imaging.md +``` \ No newline at end of file diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md index 65761d86..617ac03e 100644 --- a/docs/tutorials/plot_01_current_injection.md +++ b/docs/tutorials/plot_01_current_injection.md @@ -51,7 +51,7 @@ data (we will explain the essentials of pynapple as they are used, but see the if you are interested in learning more). After we've explored the data some, we'll introduce the Generalized Linear Model and how to fit it with NeMoS. -## Learning objectives {.keep-text} +## Learning objectives - Learn how to explore spiking data and do basic analyses using pynapple - Learn how to structure data for NeMoS @@ -86,12 +86,13 @@ this single dataset to NWB and uploaded it to the [Open Science Framework](https://osf.io/5crqj/). This allows us to easily load the data using pynapple, and it will immediately be in a format that pynapple understands! -!!! tip +:::{tip} - Pynapple can stream any NWB-formatted dataset! See [their - documentation](https://pynapple.org/examples/tutorial_pynapple_dandi.html) - for more details, and see the [DANDI Archive](https://dandiarchive.org/) - for a repository of compliant datasets. + Pynapple can stream any NWB-formatted dataset! See [their + documentation](https://pynapple.org/examples/tutorial_pynapple_dandi.html) + for more details, and see the [DANDI Archive](https://dandiarchive.org/) + for a repository of compliant datasets. +::: The first time the following cell is run, it will take a little bit of time to download the data, and a progress bar will show the download's progress. @@ -268,19 +269,20 @@ plotted together. One common way to visualize a rough estimate of firing rate is to smooth the spikes by convolving them with a Gaussian filter. -!!! info +:::{info} - This is a heuristic for getting the firing rate, and shouldn't be taken - as the literal truth (to see why, pass a firing rate through a Poisson - process to generate spikes and then smooth the output to approximate the - generating firing rate). A model should not be expected to match this - approximate firing rate exactly, but visualizing the two firing rates - together can help you reason about which phenomena in your data the model - is able to adequately capture, and which it is missing. +This is a heuristic for getting the firing rate, and shouldn't be taken +as the literal truth (to see why, pass a firing rate through a Poisson +process to generate spikes and then smooth the output to approximate the +generating firing rate). A model should not be expected to match this +approximate firing rate exactly, but visualizing the two firing rates +together can help you reason about which phenomena in your data the model +is able to adequately capture, and which it is missing. - For more information, see section 1.2 of [*Theoretical - Neuroscience*](https://boulderschool.yale.edu/sites/default/files/files/DayanAbbott.pdf), - by Dayan and Abbott. +For more information, see section 1.2 of [*Theoretical +Neuroscience*](https://boulderschool.yale.edu/sites/default/files/files/DayanAbbott.pdf), +by Dayan and Abbott. +::: Pynapple can easily compute this approximate firing rate, and plotting this information will help us pull out some phenomena that we think are @@ -391,7 +393,7 @@ current remains on. +++ -## NeMoS {.strip-code} +## NeMoS ### Preparing data @@ -415,14 +417,16 @@ following properties: [`jax.numpy`](https://jax.readthedocs.io/en/latest/jax-101/01-jax-basics.html) arrays, `numpy` arrays or `pynapple` `TsdFrame`/`Tsd`. -!!! info "What is jax?" +:::{admonition} What is jax? +:class: info - [jax](https://github.com/google/jax) is a Google-supported python library - for automatic differentiation. It has all sorts of neat features, but the - most relevant of which for NeMoS is its GPU-compatibility and - just-in-time compilation (both of which make code faster with little - overhead!), as well as the collection of optimizers present in - [jaxopt](https://jaxopt.github.io/stable/). + [jax](https://github.com/google/jax) is a Google-supported python library + for automatic differentiation. It has all sorts of neat features, but the + most relevant of which for NeMoS is its GPU-compatibility and + just-in-time compilation (both of which make code faster with little + overhead!), as well as the collection of optimizers present in + [jaxopt](https://jaxopt.github.io/stable/). +::: First, we require that our predictors and our spike counts have the same number of time bins. We can achieve this by down-sampling our current to the @@ -460,18 +464,20 @@ print(f"predictor shape: {predictor.shape}") print(f"count shape: {count.shape}") ``` -!!! info "What if I have more than one neuron?" +:::{admonition} What if I have more than one neuron? +:class: info - In this example, we're only fitting data for a single neuron, but you - might wonder how the data should be shaped if you have more than one - neuron -- do you add an extra dimension? or concatenate neurons along one - of the existing dimensions? +In this example, we're only fitting data for a single neuron, but you +might wonder how the data should be shaped if you have more than one +neuron -- do you add an extra dimension? or concatenate neurons along one +of the existing dimensions? - In NeMoS, we always fit Generalized Linear Models to a single neuron at a - time. We'll discuss this more in the [following - tutorial](../plot_02_head_direction/), but briefly: you get the same answer - whether you fit the neurons separately or simultaneously, and fitting - them separately can make your life easier. +In NeMoS, we always fit Generalized Linear Models to a single neuron at a +time. We'll discuss this more in the [following +tutorial](../plot_02_head_direction/), but briefly: you get the same answer +whether you fit the neurons separately or simultaneously, and fitting +them separately can make your life easier. +::: ### Fitting the model @@ -495,15 +501,16 @@ model objects, both of which should be one of our custom objects: Regularization modifies the objective function to reflect your prior beliefs about the parameters, such as sparsity. Regularization becomes more important as the number of input features, and thus model parameters, - grows. They can be found within `nemos.regularizer`. + grows. They can be found within [`nemos.regularizer`](regularizers). -!!! warning +:::{warning} - With a convex problem like the GLM, in theory it does not matter which - solver algorithm you use. In practice, due to numerical issues, it - generally does. Thus, it's worth trying a couple to see how their - solutions compare. (Different regularization schemes will always give - different results.) +With a convex problem like the GLM, in theory it does not matter which +solver algorithm you use. In practice, due to numerical issues, it +generally does. Thus, it's worth trying a couple to see how their +solutions compare. (Different regularization schemes will always give +different results.) +::: - Observation model: this object links the firing rate and the observed data (in this case spikes), describing the distribution of neural activity (and thus changing @@ -514,15 +521,16 @@ model objects, both of which should be one of our custom objects: For this example, we'll use an un-regularized LBFGS solver. We'll discuss regularization in a later tutorial. -!!! info "Why LBFGS?" - - [LBFGS](https://en.wikipedia.org/wiki/Limited-memory_BFGS) is a - quasi-Netwon method, that is, it uses the first derivative (the gradient) - and approximates the second derivative (the Hessian) in order to solve - the problem. This means that LBFGS tends to find a solution faster and is - often less sensitive to step-size. Try other solvers to see how they - behave! +:::{admonition} Why LBFGS? +:class: info +[LBFGS](https://en.wikipedia.org/wiki/Limited-memory_BFGS) is a +quasi-Netwon method, that is, it uses the first derivative (the gradient) +and approximates the second derivative (the Hessian) in order to solve +the problem. This means that LBFGS tends to find a solution faster and is +often less sensitive to step-size. Try other solvers to see how they +behave! +::: ```{code-cell} ipython3 @@ -562,7 +570,7 @@ It's nice to get the parameters above, but we can't tell how well our model is doing by looking at them. So how should we evaluate our model? First, we can use the model to predict the firing rates and compare that to -the smoothed spike train. By calling `predict()` we can get the model's +the smoothed spike train. By calling [`predict()`](nemos.glm.GLM.predict) we can get the model's predicted firing rate for this data. Note that this is just the output of the model's linear-nonlinear step, as described earlier! @@ -589,18 +597,18 @@ doc_plots.current_injection_plot(current, spikes, firing_rate, What do we see above? Note that the y-axes in the final row are different for each subplot! -- Predicted firing rate increases as injected current goes up — Success! :tada: +- Predicted firing rate increases as injected current goes up — Success! 🎉 - The amplitude of the predicted firing rate only matches the observed amplitude in the third interval: it's too high in the first and too low in - the second — Failure! :x: + the second — Failure! ❌ - Our predicted firing rate has the periodicity we see in the smoothed spike - train — Success! :tada: + train — Success! 🎉 - The predicted firing rate does not decay as the input remains on: the amplitudes are identical for each of the bumps within a given interval — - Failure! :x: + Failure! ❌ The failure described in the second point may seem particularly confusing — approximate amplitude feels like it should be very easy to capture, so what's @@ -665,7 +673,7 @@ poorly because of runaway excitation [$^{[1, 2]}$](#ref-1). Finally, you may want a number with which to evaluate your model's performance. As discussed earlier, the model optimizes log-likelihood to find -the best-fitting weights, and we can calculate this number using its `score` +the best-fitting weights, and we can calculate this number using its [`score`](nemos.glm.GLM.score) method: @@ -680,11 +688,12 @@ the same dataset, whether that's models using different regularizers and solvers or those using different predictors, comparing log-likelihoods is a reasonable thing to do. -!!! info +:::{info} - Under the hood, NeMoS is minimizing the negative log-likelihood, as is - typical in many optimization contexts. `score` returns the real - log-likelihood, however, and thus higher is better. +Under the hood, NeMoS is minimizing the negative log-likelihood, as is +typical in many optimization contexts. [`score`](nemos.glm.GLM.score) returns the real +log-likelihood, however, and thus higher is better. +::: Because it's un-normalized, however, the log-likelihood should not be compared across datasets (because e.g., it won't account for difference in diff --git a/pyproject.toml b/pyproject.toml index 1e01d4ee..3a707e31 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,6 +66,7 @@ docs = [ "sphinx-issues", "sphinxcontrib-apidoc", "sphinx-togglebutton", + "sphinxemoji", "myst-parser", "myst-nb", "dandi", diff --git a/src/nemos/observation_models.py b/src/nemos/observation_models.py index 1c650db2..dce49032 100644 --- a/src/nemos/observation_models.py +++ b/src/nemos/observation_models.py @@ -23,8 +23,8 @@ class Observations(Base, abc.ABC): This is an abstract base class used to implement observation models for neural data. Specific observation models that inherit from this class should define their versions - of the abstract methods: _negative_log_likelihood, emission_probability, and - residual_deviance. + of the abstract methods such as :meth:`~nemos.observation_models.Observations.log_likelihood`, :meth`~nemos.observation_models.Observations.sample_generator`, and + :meth:`~nemos.observation_models.Observations.deviance`. Attributes ---------- @@ -33,8 +33,10 @@ class Observations(Base, abc.ABC): See Also -------- - [PoissonObservations](./#nemos.observation_models.PoissonObservations) : A specific implementation of a - observation model using the Poisson distribution. + :class:`~nemos.observation_models.PoissonObservations` + A specific implementation of a observation model using the Poisson distribution. + :class:`~nemos.observation_models.GammaObservations` + A specific implementation of a observation model using the Gamma distribution. """ def __init__(self, inverse_link_function: Callable, **kwargs): @@ -239,8 +241,9 @@ def estimate_scale( :math:`f(x; \theta, \phi) \propto \exp \left(a(\phi)\left( y\theta - \mathcal{k}(\theta) \right)\right)`. The relationship between variance and the scale parameter is given by: + .. math:: - \text{var}(Y) = \frac{V(\mu)}{a(\phi)}. + \text{var}(Y) = \frac{V(\mu)}{a(\phi)}. The scale parameter, :math:`\phi`, is necessary for capturing the variance of the data accurately. From 0a03288aa5fb0e1d30fe1d8cf375d24d2cf4bd81 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 15 Nov 2024 15:53:44 -0500 Subject: [PATCH 027/107] renamed api --- docs/api_guide.rst | 6 ++-- docs/conf.py | 2 +- docs/index.md | 2 +- docs/tutorials/plot_02_head_direction.md | 45 +++++++++++++----------- 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/docs/api_guide.rst b/docs/api_guide.rst index 9dd52137..d44530a4 100644 --- a/docs/api_guide.rst +++ b/docs/api_guide.rst @@ -1,7 +1,5 @@ -.. _api_ref: - -API Guide -========= +API Reference +============= The ``nemos.glm`` module ------------------------ diff --git a/docs/conf.py b/docs/conf.py index 56f71b56..42c285c0 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -131,7 +131,7 @@ }, ], "show_prev_next": True, - "header_links_before_dropdown": 5, + "header_links_before_dropdown": 6, "navigation_depth": 3, } diff --git a/docs/index.md b/docs/index.md index e24e00cb..6660cd06 100644 --- a/docs/index.md +++ b/docs/index.md @@ -14,8 +14,8 @@ Quickstart Background How-To Guide Tutorials +API Reference Getting Help -API Guide For Developers ``` diff --git a/docs/tutorials/plot_02_head_direction.md b/docs/tutorials/plot_02_head_direction.md index f1e10cb9..776779e7 100644 --- a/docs/tutorials/plot_02_head_direction.md +++ b/docs/tutorials/plot_02_head_direction.md @@ -21,8 +21,8 @@ kernelspec: ## Learning objectives - Learn how to add history-related predictors to NeMoS GLM -- Learn about NeMoS `Basis` objects -- Learn how to use `Basis` objects with convolution +- Learn about NeMoS [`Basis`](nemos_basis) objects +- Learn how to use [`Basis`](nemos_basis) objects with convolution ```{code-cell} ipython3 import matplotlib.pyplot as plt @@ -164,7 +164,7 @@ count = nap.TsdFrame( ) ``` -## NeMoS {.strip-code} +## NeMoS It's time to use NeMoS. Our goal is to estimate the pairwise interaction between neurons. This can be quantified with a GLM if we use the recent population spike history to predict the current time step. ### Self-Connected Single Neuron @@ -200,7 +200,7 @@ Let's fix the spike history window size that we will use as predictor. # set the size of the spike history window in seconds window_size_sec = 0.8 -doc_plots.plot_history_window(neuron_count, epoch_one_spk, window_size_sec) +doc_plots.plot_history_window(neuron_count, epoch_one_spk, window_size_sec); ``` For each time point, we shift our window one bin at the time and vertically stack the spike count history in a matrix. @@ -219,7 +219,7 @@ time-points; A fast way to compute this feature matrix is convolving the counts with the identity matrix. We can apply the convolution and NaN-padding in a single step using the -[`nemos.convolve.create_convolutional_predictor`](../../../reference/nemos/convolve/#nemos.convolve.create_convolutional_predictor) +[`nemos.convolve.create_convolutional_predictor`](nemos.convolve.create_convolutional_predictor) function. @@ -253,7 +253,7 @@ We can visualize the output for a few time bins ```{code-cell} ipython3 suptitle = "Input feature: Count History" neuron_id = 0 -doc_plots.plot_features(input_feature, count.rate, suptitle) +doc_plots.plot_features(input_feature, count.rate, suptitle); ``` As you may see, the time axis is backward, this happens because convolution flips the time axis. @@ -371,7 +371,7 @@ whereas whether an input happened 51 or 55 msec ago is less important. ```{code-cell} ipython3 -doc_plots.plot_basis() +doc_plots.plot_basis(); ``` !!! info @@ -381,7 +381,7 @@ doc_plots.plot_basis() analytical step. We will eventually provide guidance on this choice, but for now we'll give you a decent choice. -NeMoS includes `Basis` objects to handle the construction and use of these +NeMoS includes [`Basis`](nemos_basis) objects to handle the construction and use of these basis functions. When we instantiate this object, the only arguments we need to specify is the @@ -454,7 +454,7 @@ print(f"Compressed count history as feature: {conv_spk.shape}") epoch_one_spk = nap.IntervalSet(8917.5, 8918.5) epoch_multi_spk = nap.IntervalSet(8979.2, 8980.2) -doc_plots.plot_convolved_counts(neuron_count, conv_spk, epoch_one_spk, epoch_multi_spk) +doc_plots.plot_convolved_counts(neuron_count, conv_spk, epoch_one_spk, epoch_multi_spk); # find interval with two spikes to show the accumulation, in a second row ``` @@ -561,7 +561,7 @@ ep = nap.IntervalSet(start=8819.4, end=8821) doc_plots.plot_rates_and_smoothed_counts( neuron_count, {"Self-connection raw history":rate_history, "Self-connection bsais": rate_basis} -) +); ``` ### All-to-all Connectivity @@ -572,8 +572,12 @@ to get an array of predictors of shape, `(num_time_points, num_neurons * num_bas #### Preparing the features - ```{code-cell} ipython3 +# re-initialize basis +basis = nmo.basis.RaisedCosineBasisLog( + n_basis_funcs=8, mode="conv", window_size=window_size +) + # convolve all the neurons convolved_count = basis.compute_features(count) ``` @@ -588,13 +592,14 @@ print(f"Convolved count shape: {convolved_count.shape}") #### Fitting the Model This is an all-to-all neurons model. -We are using the class `PopulationGLM` to fit the whole population at once. +We are using the class [`PopulationGLM`](nemos.glm.PopulationGLM) to fit the whole population at once. -!!! note - Once we condition on past activity, log-likelihood of the population is the sum of the log-likelihood - of individual neurons. Maximizing the sum (i.e. the population log-likelihood) is equivalent to - maximizing each individual term separately (i.e. fitting one neuron at the time). +:::{note} +Once we condition on past activity, log-likelihood of the population is the sum of the log-likelihood +of individual neurons. Maximizing the sum (i.e. the population log-likelihood) is equivalent to +maximizing each individual term separately (i.e. fitting one neuron at the time). +::: ```{code-cell} ipython3 @@ -619,7 +624,7 @@ Plot fit predictions over a short window not used for training. ```{code-cell} ipython3 # use pynapple for time axis for all variables plotted for tick labels in imshow doc_plots.plot_head_direction_tuning_model(tuning_curves, predicted_firing_rate, spikes, angle, threshold_hz=1, - start=8910, end=8960, cmap_label="hsv") + start=8910, end=8960, cmap_label="hsv"); ``` Let's see if our firing rate predictions improved and in what sense. @@ -632,7 +637,7 @@ doc_plots.plot_rates_and_smoothed_counts( {"Self-connection: raw history": rate_history, "Self-connection: bsais": rate_basis, "All-to-all: basis": predicted_firing_rate[:, 0]} -) +); ``` #### Visualizing the connectivity @@ -646,7 +651,7 @@ tuning = nap.compute_1d_tuning_curves_continuous(predicted_firing_rate, minmax=(0, 2 * np.pi)) ``` -Extract the weights and store it in a (n_neurons, n_neurons, n_basis_funcs) array. +Extract the weights and store it in a `(n_neurons, n_neurons, n_basis_funcs)` array. ```{code-cell} ipython3 @@ -667,5 +672,5 @@ all the coupling filters. ```{code-cell} ipython3 -doc_plots.plot_coupling(responses, tuning) +doc_plots.plot_coupling(responses, tuning); ``` From 7a62e99bfecbcb9dddf758c14964ab7fbd32a5ea Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 15 Nov 2024 15:55:53 -0500 Subject: [PATCH 028/107] renamed --- docs/{api_guide.rst => api_reference.rst} | 2 ++ 1 file changed, 2 insertions(+) rename docs/{api_guide.rst => api_reference.rst} (99%) diff --git a/docs/api_guide.rst b/docs/api_reference.rst similarity index 99% rename from docs/api_guide.rst rename to docs/api_reference.rst index d44530a4..95f7bfb9 100644 --- a/docs/api_guide.rst +++ b/docs/api_reference.rst @@ -1,3 +1,5 @@ +.. _api_ref: + API Reference ============= From 3ba0d4eb6f80984dd1c7db33382ba5947b259069 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 15 Nov 2024 16:54:43 -0500 Subject: [PATCH 029/107] fixed dark mode --- docs/assets/NeMoS_Logo_CMYK_White.svg | 1 + docs/background/README.md | 30 ++++++++++++++- docs/conf.py | 5 ++- docs/how_to_guide/README.md | 37 ++++++++++++++++++- docs/installation.md | 2 +- docs/tutorials/README.md | 45 ++++++++++++++++++++++- docs/tutorials/plot_04_v1_cells.md | 4 +- docs/tutorials/plot_05_place_cells.md | 31 +++++++++------- docs/tutorials/plot_06_calcium_imaging.md | 34 ++++++++++------- 9 files changed, 152 insertions(+), 37 deletions(-) create mode 100755 docs/assets/NeMoS_Logo_CMYK_White.svg diff --git a/docs/assets/NeMoS_Logo_CMYK_White.svg b/docs/assets/NeMoS_Logo_CMYK_White.svg new file mode 100755 index 00000000..cb453c01 --- /dev/null +++ b/docs/assets/NeMoS_Logo_CMYK_White.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/background/README.md b/docs/background/README.md index 2fdf2c7d..c4fa1093 100644 --- a/docs/background/README.md +++ b/docs/background/README.md @@ -14,12 +14,38 @@ pip install nemos[examples] ::: +::::{grid} 1 2 3 3 + +:::{grid-item-card} ```{toctree} :maxdepth: 2 -:caption: Contents plot_00_conceptual_intro.md +``` +::: + +:::{grid-item-card} +```{toctree} +:maxdepth: 2 + plot_01_1D_basis_function.md +``` +::: + +:::{grid-item-card} +```{toctree} +:maxdepth: 2 + plot_02_ND_basis_function.md +``` +::: + +:::{grid-item-card} +```{toctree} +:maxdepth: 2 + plot_03_1D_convolution.md -``` \ No newline at end of file +``` +::: + +:::: diff --git a/docs/conf.py b/docs/conf.py index 42c285c0..6b04518e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -111,7 +111,6 @@ html_theme = 'pydata_sphinx_theme' -html_logo = "assets/NeMoS_Logo_CMYK_Full.svg" html_favicon = "assets/NeMoS_favicon.ico" # Additional theme options @@ -133,6 +132,10 @@ "show_prev_next": True, "header_links_before_dropdown": 6, "navigation_depth": 3, + "logo": { + "image_light": "_static/NeMoS_Logo_CMYK_Full.svg", + "image_dark": "_static/NeMoS_Logo_CMYK_White.svg", + } } html_context = { diff --git a/docs/how_to_guide/README.md b/docs/how_to_guide/README.md index a7a5a231..188fe5b2 100644 --- a/docs/how_to_guide/README.md +++ b/docs/how_to_guide/README.md @@ -14,13 +14,46 @@ pip install nemos[examples] ::: +::::{grid} 1 2 3 3 + +:::{grid-item-card} ```{toctree} :maxdepth: 2 -:caption: Contents plot_02_glm_demo.md +``` +::: + +:::{grid-item-card} +```{toctree} +:maxdepth: 2 + plot_03_population_glm.md +``` +::: + +:::{grid-item-card} +```{toctree} +:maxdepth: 2 + plot_04_batch_glm.md +``` +::: + +:::{grid-item-card} +```{toctree} +:maxdepth: 2 + plot_05_sklearn_pipeline_cv_demo.md +``` +::: + +:::{grid-item-card} +```{toctree} +:maxdepth: 2 + plot_06_glm_pytree.md -``` \ No newline at end of file +``` +::: + +:::: diff --git a/docs/installation.md b/docs/installation.md index 49410ed6..b8cfd47e 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -1,4 +1,4 @@ - +# Install ## Prerequisites diff --git a/docs/tutorials/README.md b/docs/tutorials/README.md index 909f4364..54f9845b 100644 --- a/docs/tutorials/README.md +++ b/docs/tutorials/README.md @@ -12,14 +12,55 @@ pip install nemos[examples] ``` ::: +::::{grid} 1 2 3 3 + +:::{grid-item-card} ```{toctree} :maxdepth: 2 -:caption: Contents plot_01_current_injection.md +``` +::: + +:::{grid-item-card} +```{toctree} +:maxdepth: 2 + plot_02_head_direction.md +``` +::: + +:::{grid-item-card} +```{toctree} +:maxdepth: 2 + plot_03_grid_cells.md +``` +::: + + +:::{grid-item-card} +```{toctree} +:maxdepth: 2 + plot_04_v1_cells.md +``` +::: + + +:::{grid-item-card} +```{toctree} +:maxdepth: 2 + plot_05_place_cells.md +``` +::: + +:::{grid-item-card} +```{toctree} +:maxdepth: 2 plot_06_calcium_imaging.md -``` \ No newline at end of file +``` +::: + +:::: \ No newline at end of file diff --git a/docs/tutorials/plot_04_v1_cells.md b/docs/tutorials/plot_04_v1_cells.md index 8a55c83d..cfe594b9 100644 --- a/docs/tutorials/plot_04_v1_cells.md +++ b/docs/tutorials/plot_04_v1_cells.md @@ -166,7 +166,7 @@ sta = nap.compute_event_trigger_average(spikes, stimulus, binsize=0.025, windowsize=(-0.15, 0.0)) ``` -sta is a `TsdTensor`, which gives us the 2d receptive field at each of the +sta is a [`TsdTensor`](https://pynapple.org/generated/pynapple.core.time_series.TsdTensor.html), which gives us the 2d receptive field at each of the time points. @@ -291,7 +291,7 @@ filtered_stimulus We can see that the time points are now aligned, and we've filled forward the values the way we'd like. -Now, similar to the [head direction tutorial](../plot_02_head_direction), we'll +Now, similar to the [head direction tutorial](plot_02_head_direction), we'll use the log-stretched raised cosine basis to create the predictor for our GLM: diff --git a/docs/tutorials/plot_05_place_cells.md b/docs/tutorials/plot_05_place_cells.md index ed81e904..59e81eae 100644 --- a/docs/tutorials/plot_05_place_cells.md +++ b/docs/tutorials/plot_05_place_cells.md @@ -34,6 +34,9 @@ from nemos import _documentation_utils as doc_plots # configure plots some plt.style.use(nmo.styles.plot_style) + +# shut down jax to numpy conversion warning +nap.nap_config.suppress_conversion_warnings = True ``` ## Data Streaming @@ -118,7 +121,7 @@ for i, n in enumerate(order): ## Phase precession -In addition to place modulation, place cells are also modulated by the theta oscillation. The phase at which neurons fire is dependant of the position. This phenomen is called "phase precession" (see [J. O’Keefe, M. L. Recce, "Phase relationship between hippocampal place units and the EEG theta rhythm." Hippocampus 3, 317–330 (1993).](https://doi.org/10.1002/hipo.450030307) +In addition to place modulation, place cells are also modulated by the theta oscillation. The phase at which neurons fire is dependant of the position. This phenomen is called "phase precession" (see [J. O’Keefe, M. L. Recce, "Phase relationship between hippocampal place units and the EEG theta rhythm." Hippocampus 3, 317–330 (1993).](https://doi.org/10.1002/hipo.450030307)). Let's compute the response of the neuron as a function of both theta and position. The phase of theta has already been computed but we have to bring it to the same dimension as the position feature. While the position has been sampled at 40Hz, the theta phase has been computed at 1250Hz. Later on during the analysis, we will use a bin size of 5 ms for counting the spikes. Since this corresponds to an intermediate frequency between 40 and 1250 Hz, we will bring all the features to 200Hz already. @@ -142,7 +145,7 @@ data = nap.TsdFrame( print(data) ``` -`data` is a `TsdFrame` that contains the position and phase. Before calling `compute_2d_tuning_curves` from pynapple to observe the theta phase precession, we will restrict the analysis to the place field of one neuron. +`data` is a [`TsdFrame`](https://pynapple.org/generated/pynapple.core.time_series.TsdTensor.html) that contains the position and phase. Before calling [`compute_2d_tuning_curves`](https://pynapple.org/generated/pynapple.process.tuning_curves.html#pynapple.process.tuning_curves.compute_2d_tuning_curves) from pynapple to observe the theta phase precession, we will restrict the analysis to the place field of one neuron. There are a lot of neurons but for this analysis, we will focus on one neuron only. @@ -163,7 +166,7 @@ This neurons place field is between 0 and 60 cm within the linear track. Here we within_ep = position.threshold(60.0, method="below").time_support ``` -`within_ep` is an `IntervalSet`. We can now give it to `compute_2d_tuning_curves` along with the spiking activity and the position-phase features. +`within_ep` is an [`IntervalSet`](https://pynapple.org/generated/pynapple.core.interval_set.IntervalSet.html). We can now give it to [`compute_2d_tuning_curves`](https://pynapple.org/generated/pynapple.process.tuning_curves.html#pynapple.process.tuning_curves.compute_2d_tuning_curves) along with the spiking activity and the position-phase features. ```{code-cell} ipython3 @@ -219,14 +222,14 @@ for s, e in data.time_support.values: # Time support contains the epochs speed = nap.Tsd(t=data.t, d=np.hstack(speed), time_support=data.time_support) ``` -Now that we have the speed of the animal, we can compute the tuning curves for speed modulation. Here we call pynapple `compute_1d_tuning_curves`: +Now that we have the speed of the animal, we can compute the tuning curves for speed modulation. Here we call pynapple [`compute_1d_tuning_curves`](https://pynapple.org/generated/pynapple.process.tuning_curves.html#pynapple.process.tuning_curves.compute_1d_tuning_curves): ```{code-cell} ipython3 tc_speed = nap.compute_1d_tuning_curves(spikes, speed, 20) ``` -To assess the variabilty in speed when the animal is travering the linear track, we can compute the average speed and estimate the standard deviation. Here we use numpy only and put the results in a pandas `DataFrame`: +To assess the variabilty in speed when the animal is travering the linear track, we can compute the average speed and estimate the standard deviation. Here we use numpy only and put the results in a pandas [`DataFrame`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html): ```{code-cell} ipython3 @@ -285,9 +288,9 @@ print(count.shape) For each feature, we will use a different set of basis : - - position : `nmo.basis.MSplineBasis` - - theta phase : `nmo.basis.CyclicBSplineBasis` - - speed : `nmo.basis.MSplineBasis` + - position : [`MSplineBasis`](nemos.basis.MSplineBasis) + - theta phase : [`CyclicBSplineBasis`](nemos.basis.CyclicBSplineBasis) + - speed : [`MSplineBasis`](nemos.basis.MSplineBasis) ```{code-cell} ipython3 @@ -335,7 +338,7 @@ glm.fit(X, count) ## Prediction -Let's check first if our model can accurately predict the different tuning curves we displayed above. We can use the `predict` function of NeMoS and then compute new tuning curves +Let's check first if our model can accurately predict the different tuning curves we displayed above. We can use the [`predict`](nemos.glm.GLM.predict) function of NeMoS and then compute new tuning curves ```{code-cell} ipython3 @@ -367,9 +370,10 @@ fig = doc_plots.plot_position_phase_speed_tuning( While this model captures nicely the features-rate relationship, it is not necessarily the simplest model. Let's construct several models and evaluate their score to determine the best model. -!!! note - To shorten this notebook, only a few combinations are tested. Feel free to expand this list. +:::{note} +To shorten this notebook, only a few combinations are tested. Feel free to expand this list. +::: ```{code-cell} ipython3 @@ -440,8 +444,9 @@ plt.tight_layout() Some models are doing better than others. -!!! warning - A proper model comparison should be done by scoring models repetitively on various train and test set. Here we are only doing partial models comparison for the sake of conciseness. +:::{warning} +A proper model comparison should be done by scoring models repetitively on various train and test set. Here we are only doing partial models comparison for the sake of conciseness. +::: Alternatively, we can plot some tuning curves to compare each models visually. diff --git a/docs/tutorials/plot_06_calcium_imaging.md b/docs/tutorials/plot_06_calcium_imaging.md index 06e78296..632abfeb 100644 --- a/docs/tutorials/plot_06_calcium_imaging.md +++ b/docs/tutorials/plot_06_calcium_imaging.md @@ -69,7 +69,7 @@ transients = data['RoiResponseSeries'] print(transients) ``` -`transients` is a `TsdFrame`. Each column contains the activity of one neuron. +`transients` is a [`TsdFrame`](https://pynapple.org/generated/pynapple.core.time_series.TsdTensor.html). Each column contains the activity of one neuron. The mouse was recorded for a 20 minute recording epoch as we can see from the `time_support` property of the `transients` object. @@ -99,8 +99,8 @@ You can see that the calcium signals are both nonnegative, and noisy. One (neuro +++ -We can also plot tuning curves, plotting mean calcium activity as a function of head direction, using the function `compute_1d_tuning_curves_continuous`. -Here `data['ry']` is a `Tsd` that contains the angular head-direction of the animal between 0 and 2$\pi$. +We can also plot tuning curves, plotting mean calcium activity as a function of head direction, using the function [`compute_1d_tuning_curves_continuous`](https://pynapple.org/generated/pynapple.process.tuning_curves.html#pynapple.process.tuning_curves.compute_1d_tuning_curves_continuous). +Here `data['ry']` is a [`Tsd`](https://pynapple.org/generated/pynapple.core.time_series.Tsd.html) that contains the angular head-direction of the animal between 0 and 2$\pi$. ```{code-cell} ipython3 @@ -159,7 +159,7 @@ heading_basis = nmo.basis.CyclicBSplineBasis(n_basis_funcs=12) coupling_basis = nmo.basis.RaisedCosineBasisLog(3, mode="conv", window_size=10) ``` -We need to make sure the design matrix will be full-rank by applying identifiability constraints to the Cyclic Bspline, and then combine the bases (the resturned object will be an `AdditiveBasis` object). +We need to make sure the design matrix will be full-rank by applying identifiability constraints to the Cyclic Bspline, and then combine the bases (the resturned object will be an [`AdditiveBasis`](nemos.basis.AdditiveBasis) object). ```{code-cell} ipython3 @@ -170,8 +170,11 @@ basis = heading_basis + coupling_basis ## Gamma GLM Until now, we have been modeling spike trains, and have used a Poisson distribution for the observation model. With calcium traces, things are quite different: we no longer have counts but continuous signals, so the Poisson assumption is no longer appropriate. A Gaussian model is also not ideal since the calcium traces are non-negative. To satisfy these constraints, we will use a Gamma distribution from NeMoS with a soft-plus non linearity. -!!! note "Non-linearity" - Different option are possible. With a soft-plus we are assuming an "additive" effect of the predictors, while an exponential non-linearity assumes multiplicative effects. Deciding which firing rate model works best is an empirical question. You can fit different configurations to see which one capture best the neural activity. +:::{admonirion} Non-linearity +:class: note + +Different option are possible. With a soft-plus we are assuming an "additive" effect of the predictors, while an exponential non-linearity assumes multiplicative effects. Deciding which firing rate model works best is an empirical question. You can fit different configurations to see which one capture best the neural activity. +::: ```{code-cell} ipython3 @@ -196,7 +199,7 @@ print(selected_neurons) ``` We need to bring the head-direction of the animal to the same size as the transients matrix. -We can use the function `bin_average` of pynapple. Notice how we pass the parameter `ep` +We can use the function [`bin_average`](https://pynapple.org/generated/pynapple.core.time_series.Tsd.bin_average.html#pynapple.core.time_series.Tsd.bin_average) of pynapple. Notice how we pass the parameter `ep` that is the `time_support` of the transients. @@ -224,7 +227,7 @@ X = basis.compute_features(head_direction, Y[:, selected_neurons]) ## Train & test set -Let's create a train epoch and a test epoch to fit and test the models. Since `X` is a pynapple time series, we can create `IntervalSet` objects to restrict them into a train set and test set. +Let's create a train epoch and a test epoch to fit and test the models. Since `X` is a pynapple time series, we can create [`IntervalSet`](https://pynapple.org/generated/pynapple.core.interval_set.IntervalSet.html) objects to restrict them into a train set and test set. ```{code-cell} ipython3 @@ -305,7 +308,7 @@ plt.show() While there is some variability in the fit for both models, one advantage of the gamma distribution is clear: the nonnegativity constraint is followed with the data. This is required for using GLMs to predict the firing rate, which must be positive, in response to simulated inputs. See Peyrache et al. 2018[$^{[1]}$](#ref-1) for an example of simulating activity with a GLM. -Another way to compare models is to compute tuning curves. Here we use the function `compute_1d_tuning_curves_continuous` from pynapple. +Another way to compare models is to compute tuning curves. Here we use the function [`compute_1d_tuning_curves_continuous`](https://pynapple.org/generated/pynapple.process.tuning_curves.html#pynapple.process.tuning_curves.compute_1d_tuning_curves_continuous) from pynapple. ```{code-cell} ipython3 @@ -328,11 +331,14 @@ plt.xlabel("Head-direction (rad)") plt.show() ``` -!!! note "Gamma-GLM for Calcium Imaging Analysis" - Using Gamma-GLMs for fitting calcium imaging data is still in early stages, and hasn't been through - the levels of review and validation that they have for fitting spike data. Users should consider - this a relatively unexplored territory, and we hope that we hope that NeMoS will help researchers - explore this new space of models. +:::{admonition} Gamma-GLM for Calcium Imaging Analysis +:class: note + +Using Gamma-GLMs for fitting calcium imaging data is still in early stages, and hasn't been through +the levels of review and validation that they have for fitting spike data. Users should consider +this a relatively unexplored territory, and we hope that we hope that NeMoS will help researchers +explore this new space of models. +::: ## References From c43c6f912c5c11fd458dd54c35bc22285721cec2 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 15 Nov 2024 17:12:36 -0500 Subject: [PATCH 030/107] fixed quickstart --- docs/_templates/layout.html | 16 ++++++++++++ docs/assets/stylesheets/custom.css | 42 ++++++++++++++++++++++++++++++ docs/conf.py | 4 +-- docs/quickstart.md | 26 +++++++++++------- 4 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 docs/_templates/layout.html diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html new file mode 100644 index 00000000..1ab3da93 --- /dev/null +++ b/docs/_templates/layout.html @@ -0,0 +1,16 @@ +{% extends "!layout.html" %} + +{%- block footer %} +
+
+
+

+ {% trans copyright=copyright|e %}© Copyright {{ copyright }}, Edoardo Balzani.{% endtrans %}
+ Created using Sphinx and the PyData Theme.
+

+
+
v{{ version }}
+
+
+ +{%- endblock %} \ No newline at end of file diff --git a/docs/assets/stylesheets/custom.css b/docs/assets/stylesheets/custom.css index 2d83a40d..32c2935d 100644 --- a/docs/assets/stylesheets/custom.css +++ b/docs/assets/stylesheets/custom.css @@ -93,3 +93,45 @@ html[data-theme=light]{ .toctree-l4 { font-weight: normal; } + +/* Add a line separator above the entire footnote list */ +aside.footnote-list { + border-top: 1px solid #ccc; /* Add a horizontal line */ + margin-top: 2em; /* Space above the separator */ + padding-top: 1em; /* Space below the separator */ +} + +/* Style each individual footnote */ +aside.footnote { + margin-bottom: 1em; /* Add space between footnotes */ + font-size: 0.9em; /* Adjust font size */ + color: #333; /* Text color */ +} + +/* Style the label (the bracketed number) */ +aside.footnote .label { + font-weight: bold; /* Make it stand out */ + margin-right: 0.5em; /* Add space after the label */ +} + +/* Style the brackets */ +span.fn-bracket { + color: #666; /* Dim the brackets */ +} + +/* Style the links within the footnotes */ +aside.footnote a { + color: #007BFF; /* Blue link color */ + text-decoration: none; /* Remove underline */ +} + +aside.footnote a:hover { + text-decoration: underline; /* Add underline on hover */ +} + +/* Adjust spacing for the paragraph inside the footnote */ +aside.footnote p { + margin: 0.5em 0; + line-height: 1.5; /* Improve readability */ +} + diff --git a/docs/conf.py b/docs/conf.py index 6b04518e..824ec33c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -30,8 +30,8 @@ project = 'nemos' -copyright = '2024, SJ Venditto' -author = 'SJ Venditto' +copyright = '2024' +author = 'E Balzani' version = release = nemos.__version__ # -- General configuration --------------------------------------------------- diff --git a/docs/quickstart.md b/docs/quickstart.md index 94dd6a75..4507903a 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -211,8 +211,11 @@ Once the basis is initialized, you can call `compute_features` on an input of sh `(n_samples, n_signals)` to perform the convolution. The output will be a 2-dimensional array of shape `(n_samples, n_basis_funcs)` or `(n_samples, n_basis_funcs * n_signals)` respectively. -!!! warning "Signal length and window size" - The `window_size` must be shorter than the number of samples in the signal(s) being convolved. +:::{admonition} Signal length and window size +:class: warning + +The `window_size` must be shorter than the number of samples in the signal(s) being convolved. +::: ```python @@ -279,11 +282,11 @@ You can specify the regularization scheme and its strength when initializing the ## **Pre-processing with `pynapple`** -!!! warning - - This section assumes some familiarity with the `pynapple` package for time series manipulation and data - exploration. If you'd like to learn more about it, take a look at the [`pynapple` documentation](https://pynapple-org.github.io/pynapple/). +:::{info} +This section assumes some familiarity with the `pynapple` package for time series manipulation and data +exploration. If you'd like to learn more about it, take a look at the [`pynapple` documentation](https://pynapple-org.github.io/pynapple/). +::: `pynapple` is an extremely helpful tool when working with time series data. You can easily perform operations such as restricting your time series to specific epochs (sleep/wake, context A vs. context B, etc.), as well as common @@ -321,9 +324,10 @@ A canonical example of this behavior is the `predict` method of `GLM`. Let's see how you can greatly streamline your analysis pipeline by integrating `pynapple` and NeMoS. -!!! note - You can download this dataset by clicking [here](https://www.dropbox.com/s/su4oaje57g3kit9/A2929-200711.zip?dl=1). +:::{note} +You can download this dataset by clicking [here](https://www.dropbox.com/s/su4oaje57g3kit9/A2929-200711.zip?dl=1). +::: ```python @@ -426,9 +430,11 @@ Fit a 5-fold cross-validation scheme for comparing two different regularizer str ``` -!!! info "Cross-Validation in NeMoS" +:::{admonition} Cross-Validation in NeMoS +:class: info - For more information and a practical example on how to construct a parameter grid and cross-validate hyperparameters across an entire pipeline, please refer to the [tutorial on pipelining and cross-validation](../generated/how_to_guide/plot_06_sklearn_pipeline_cv_demo). +For more information and a practical example on how to construct a parameter grid and cross-validate hyperparameters across an entire pipeline, please refer to the [tutorial on pipelining and cross-validation](../generated/how_to_guide/plot_06_sklearn_pipeline_cv_demo). +::: Finally, we can print the regularizer strength with the best cross-validated performance: From f17e0097b6f7034de78d1bd4f7ec58054a0b5854 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 15 Nov 2024 17:47:09 -0500 Subject: [PATCH 031/107] finished glm note --- .../classes_nemos.png | Bin .../classes_nemos.svg | 0 docs/developers_notes/01-base_class.md | 7 +-- docs/developers_notes/02-base_regressor.md | 34 +++++++------ docs/developers_notes/03-glm.md | 45 +++++++++--------- .../developers_notes/05-observation_models.md | 1 + docs/developers_notes/06-regularizer.md | 1 + docs/developers_notes/README.md | 16 ++++++- 8 files changed, 64 insertions(+), 40 deletions(-) rename docs/{developers_notes => assets}/classes_nemos.png (100%) rename docs/{developers_notes => assets}/classes_nemos.svg (100%) diff --git a/docs/developers_notes/classes_nemos.png b/docs/assets/classes_nemos.png similarity index 100% rename from docs/developers_notes/classes_nemos.png rename to docs/assets/classes_nemos.png diff --git a/docs/developers_notes/classes_nemos.svg b/docs/assets/classes_nemos.svg similarity index 100% rename from docs/developers_notes/classes_nemos.svg rename to docs/assets/classes_nemos.svg diff --git a/docs/developers_notes/01-base_class.md b/docs/developers_notes/01-base_class.md index 8050a6c8..70de4276 100644 --- a/docs/developers_notes/01-base_class.md +++ b/docs/developers_notes/01-base_class.md @@ -4,7 +4,7 @@ The `base_class` module introduces the `Base` class and abstract classes defining broad model categories and feature constructors. These abstract classes **must** inherit from `Base`. -The `Base` class is envisioned as the foundational component for any object type (e.g., basis, regression, dimensionality reduction, clustering, observation models, regularizers etc.). In contrast, abstract classes derived from `Base` define overarching object categories (e.g., `base_regressor.BaseRegressor` is building block for GLMs, GAMS, etc. while `observation_models.Observations` is the building block for the Poisson observations, Gamma observations, ... etc.). +The `Base` class is envisioned as the foundational component for any object type (e.g., basis, regression, dimensionality reduction, clustering, observation models, regularizers etc.). In contrast, abstract classes derived from `Base` define overarching object categories (e.g., `base_regressor.BaseRegressor` is building block for GLMs, GAMS, etc. while [`observation_models.Observations`](nemos.observation_models.Observations) is the building block for the Poisson observations, Gamma observations, ... etc.). Designed to be compatible with the `scikit-learn` API, the class structure aims to facilitate access to `scikit-learn`'s robust pipeline and cross-validation modules. This is achieved while leveraging the accelerated computational capabilities of `jax` and `jaxopt` in the backend, which is essential for analyzing extensive neural recordings and fitting large models. @@ -47,8 +47,9 @@ The `Base` class aligns with the `scikit-learn` API for `base.BaseEstimator`. Th For a detailed understanding, consult the [`scikit-learn` API Reference](https://scikit-learn.org/stable/modules/classes.html) and [`BaseEstimator`](https://scikit-learn.org/stable/modules/generated/sklearn.base.BaseEstimator.html). -!!! Note - We've intentionally omitted the `get_metadata_routing` method. Given its current experimental status and its lack of relevance to the `GLM` class, this method was excluded. Should future needs arise around parameter routing, consider directly inheriting from `sklearn.BaseEstimator`. More information can be found [here](https://scikit-learn.org/stable/metadata_routing.html#metadata-routing). +:::{note} +We've intentionally omitted the `get_metadata_routing` method. Given its current experimental status and its lack of relevance to the [`GLM`](nemos.glm.GLM) class, this method was excluded. Should future needs arise around parameter routing, consider directly inheriting from `sklearn.BaseEstimator`. More information can be found [here](https://scikit-learn.org/stable/metadata_routing.html#metadata-routing). +::: ### Public methods diff --git a/docs/developers_notes/02-base_regressor.md b/docs/developers_notes/02-base_regressor.md index 2e03e751..d29887e5 100644 --- a/docs/developers_notes/02-base_regressor.md +++ b/docs/developers_notes/02-base_regressor.md @@ -1,21 +1,24 @@ # The Abstract Class `BaseRegressor` -`BaseRegressor` is an abstract class that inherits from `Base`, stipulating the implementation of number of abstract methods such as `fit`, `predict`, `score`. This ensures seamless assimilation with `scikit-learn` pipelines and cross-validation procedures. +`BaseRegressor` is an abstract class that inherits from `Base`, stipulating the implementation of number of abstract methods such as [`fit`](nemos.glm.GLM.fit), [`predict`](nemos.glm.GLM.predict), [`score`](nemos.glm.GLM.score). This ensures seamless assimilation with `scikit-learn` pipelines and cross-validation procedures. -!!! Example - The current package version includes a concrete class named `nemos.glm.GLM`. This class inherits from `BaseRegressor`, which in turn inherits `Base`, since it falls under the "GLM regression" category. - As a `BaseRegressor`, it **must** implement the `fit`, `score`, `predict` and the other abstract methods of this class, see below. +:::{admonition} Example +:class: note + +The current package version includes a concrete class named [`nemos.glm.GLM`](nemos.glm.GLM). This class inherits from `BaseRegressor`, which in turn inherits `Base`, since it falls under the "GLM regression" category. +As a `BaseRegressor`, it **must** implement the [`fit`](nemos.glm.GLM.fit), [`score`](nemos.glm.GLM.score), [`predict`](nemos.glm.GLM.predict) and the other abstract methods of this class, see below. +::: ### Abstract Methods For subclasses derived from `BaseRegressor` to function correctly, they must implement the following: -1. `fit`: Adapt the model using input data `X` and corresponding observations `y`. -2. `predict`: Provide predictions based on the trained model and input data `X`. -3. `score`: Score the accuracy of model predictions using input data `X` against the actual observations `y`. -4. `simulate`: Simulate data based on the trained regression model. -5. `update`: Run a single optimization step, and stores the updated parameter and solver state. Used by stochastic optimization schemes. +1. [`fit`](nemos.glm.GLM.fit): Adapt the model using input data `X` and corresponding observations `y`. +2. [`predict`](nemos.glm.GLM.predict): Provide predictions based on the trained model and input data `X`. +3. [`score`](nemos.glm.GLM.score): Score the accuracy of model predictions using input data `X` against the actual observations `y`. +4. [`simulate`](nemos.glm.GLM.simulate): Simulate data based on the trained regression model. +5. [`update`](nemos.glm.GLM.update): Run a single optimization step, and stores the updated parameter and solver state. Used by stochastic optimization schemes. 6. `_predict_and_compute_loss`: Compute prediction and evaluates the loss function prvided the parameters and `X` and `y`. This is used by the `instantiate_solver` method which sets up the solver. 7. `_check_params`: Check the parameter structure. 8. `_check_input_dimensionality`: Check the input dimensionality matches model expectation. @@ -29,7 +32,7 @@ input and parameters conform with the model requirements. Public attributes are stored as properties: -- `regularizer`: An instance of the `nemos.regularizer.Regularizer` class. The setter for this property accepts either the instance directly or a string that is used to instantiate the appropriate regularizer. +- `regularizer`: An instance of the [`nemos.regularizer.Regularizer`](nemos.regularizer.Regularizer) class. The setter for this property accepts either the instance directly or a string that is used to instantiate the appropriate regularizer. - `regularizer_strength`: A float quantifying the amount of regularization. - `solver_name`: One of the `jaxopt` solver supported solvers, currently "GradientDescent", "BFGS", "LBFGS", "ProximalGradient" and, "NonlinearCG". - `solver_kwargs`: Extra keyword arguments to be passed at solver initialization. @@ -37,11 +40,14 @@ Public attributes are stored as properties: When implementing a new subclass of `BaseRegressor`, the only attributes you must interact directly with are those that operate on the solver, i.e. `solver_init_state`, `solver_update`, `solver_run`. -Typically, in `YourRegressor` you will call `self.solver_init_state` at the parameter initialization step, `self.sovler_run` in `fit`, and `self.solver_update` in `update`. +Typically, in `YourRegressor` you will call `self.solver_init_state` at the parameter initialization step, `self.sovler_run` in [`fit`](nemos.glm.GLM.fit), and `self.solver_update` in [`update`](nemos.glm.GLM.update). + +:::{admonition} Solvers +:class: note -!!! note "Solvers" - Solvers are typically optimizers from the `jaxopt` package, but in principle they could be custom optimization routines as long as they respect the `jaxopt` api (i.e., have a `run`, `init_state`, and `update` method with the appropriate input/output types). - We rely on `jaxopt` because it provides a comprehensive set of robust, GPU accelerated, batchable and differentiable optimizers in JAX, that are highly customizable. In the future we may provide a number of custom solvers optimized for convex stochastic optimization. +Solvers are typically optimizers from the `jaxopt` package, but in principle they could be custom optimization routines as long as they respect the `jaxopt` api (i.e., have a `run`, `init_state`, and [`update`](nemos.glm.GLM.update) method with the appropriate input/output types). +We rely on `jaxopt` because it provides a comprehensive set of robust, GPU accelerated, batchable and differentiable optimizers in JAX, that are highly customizable. In the future we may provide a number of custom solvers optimized for convex stochastic optimization. +::: ## Contributor Guidelines diff --git a/docs/developers_notes/03-glm.md b/docs/developers_notes/03-glm.md index 3eb5928b..29e2915d 100644 --- a/docs/developers_notes/03-glm.md +++ b/docs/developers_notes/03-glm.md @@ -6,20 +6,20 @@ Generalized Linear Models (GLM) provide a flexible framework for modeling a variety of data types while establishing a relationship between multiple predictors and a response variable. A GLM extends the traditional linear regression by allowing for response variables that have error distribution models other than a normal distribution, such as binomial or Poisson distributions. -The `nemos.glm` module currently offers implementations of two GLM classes: +The [`nemos.glm`](nemos_glm) module currently offers implementations of two GLM classes: -1. **`GLM`:** A direct implementation of a feedforward GLM. -2. **`PopulationGLM`:** An implementation of a GLM for fitting a populaiton of neuron in a vectorized manner. This class inherits from `GLM` and redefines the `fit` and `_predict` to fit the model and predict the firing rate. +1. [`GLM`](nemos.glm.GLM): A direct implementation of a feedforward GLM. +2. [`PopulationGLM`](nemos.glm.PopulationGLM): An implementation of a GLM for fitting a populaiton of neuron in a vectorized manner. This class inherits from [`GLM`](nemos.glm.GLM) and redefines the [`fit`](nemos.glm.GLM.fit) and `_predict` to fit the model and predict the firing rate. Our design aligns with the `scikit-learn` API, facilitating seamless integration of our GLM classes with the well-established `scikit-learn` pipeline and its cross-validation tools. The classes provided here are modular by design offering a standard foundation for any GLM variant. -Instantiating a specific GLM simply requires providing an observation model (Gamma, Poisson, etc.), a regularization strategies (Ridge, Lasso, etc.) and an optimization scheme during initialization. This is done using the [`nemos.observation_models.Observations`](../05-observation_models/#the-abstract-class-observations), [`nemos.regularizer.Regularizer`](../06-regularizer/#the-abstract-class-regularizer) objects as well as the compatible `jaxopt` solvers, respectively. +Instantiating a specific GLM simply requires providing an observation model (Gamma, Poisson, etc.), a regularization strategies (Ridge, Lasso, etc.) and an optimization scheme during initialization. This is done using the [`nemos.observation_models.Observations`](the-abstract-class-observations), [`nemos.regularizer.Regularizer`](the-abstract-class-regularizer) objects as well as the compatible `jaxopt` solvers, respectively.
- +
Schematic of the module interactions.
@@ -27,32 +27,33 @@ Instantiating a specific GLM simply requires providing an observation model (Gam ## The Concrete Class `GLM` -The `GLM` class provides a direct implementation of the GLM model and is designed with `scikit-learn` compatibility in mind. +The [`GLM`](nemos.glm.GLM) class provides a direct implementation of the GLM model and is designed with `scikit-learn` compatibility in mind. ### Inheritance -`GLM` inherits from [`BaseRegressor`](../02-base_regressor/#the-abstract-class-baseregressor). This inheritance mandates the direct implementation of methods like `predict`, `fit`, `score` `update`, and `simulate`, plus a number of validation methods. +[`GLM`](nemos.glm.GLM) inherits from [`BaseRegressor`](../02-base_regressor/#the-abstract-class-baseregressor). This inheritance mandates the direct implementation of methods like [`predict`](nemos.glm.GLM.predict), [`fit`](nemos.glm.GLM.fit), [`score`](nemos.glm.GLM.score), [`update`](nemos.glm.GLM.update), and [`simulate`(nemos.glm.GLM.[`GLM`](nemos.glm.GLM) inherits from [`BaseRegressor`](../02-base_regressor/#the-abstract-class-baseregressor). This inheritance mandates the direct implementation of methods like [`predict`](nemos.glm.GLM.predict), [`fit`](nemos.glm.GLM.fit), [`score`](nemos.glm.GLM.score), [`update`](nemos.glm.GLM.update), and [`simulate`](nemos.glm.GLM.simulate), plus a number of validation methods. +), plus a number of validation methods. ### Attributes -- **`observation_model`**: Property that represents the GLM observation model, which is an object of the [`nemos.observation_models.Observations`](../05-observation_models/#the-abstract-class-observations) type. This model determines the log-likelihood and the emission probability mechanism for the `GLM`. +- **`observation_model`**: Property that represents the GLM observation model, which is an object of the [`nemos.observation_models.Observations`](the-abstract-class-observations) type. This model determines the log-likelihood and the emission probability mechanism for the [`GLM`](nemos.glm.GLM). - **`coef_`**: Stores the solution for spike basis coefficients as `jax.ndarray` after the fitting process. It is initialized as `None` during class instantiation. - **`intercept_`**: Stores the bias terms' solutions as `jax.ndarray` after the fitting process. It is initialized as `None` during class instantiation. - **`dof_resid_`**: The degrees of freedom of the model's residual. this quantity is used to estimate the scale parameter, see below, and compute frequentist confidence intervals. - **`scale_`**: The scale parameter of the observation distribution, which together with the rate, uniquely specifies a distribution of the exponential family. Example: a 1D Gaussian is specified by the mean which is the rate, and the standard deviation, which is the scale. - **`solver_state_`**: Indicates the solver's state. For specific solver states, refer to the [`jaxopt` documentation](https://jaxopt.github.io/stable/index.html#). -Additionally, the `GLM` class inherits the attributes of `BaseRegressor`, see the [relative note](02-base_regressor.md) for more information. +Additionally, the [`GLM`](nemos.glm.GLM) class inherits the attributes of `BaseRegressor`, see the [relative note](02-base_regressor.md) for more information. ### Public Methods -- **`predict`**: Validates input and computes the mean rates of the `GLM` by invoking the inverse-link function of the `observation_models` attribute. -- **`score`**: Validates input and assesses the Poisson GLM using either log-likelihood or pseudo-$R^2$. This method uses the `observation_models` to determine log-likelihood or pseudo-$R^2$. -- **`fit`**: Validates input and aligns the Poisson GLM with spike train data. It leverages the `observation_models` and `regularizer` to define the model's loss function and instantiate the regularizer. -- **`simulate`**: Simulates spike trains using the GLM as a feedforward network, invoking the `observation_models.sample_generator` method for emission probability. -- **`initialize_params`**: Initialize model parameters, setting to zero the coefficients, and setting the intercept by matching the firing rate. -- **`initialize_state`**: Initialize the state of the solver. -- **`update`**: Run a step of optimization and update the parameter and solver step. +- [`predict`](nemos.glm.GLM.predict): Validates input and computes the mean rates of the [`GLM`](nemos.glm.GLM) by invoking the inverse-link function of the `observation_models` attribute. +- [`score`](nemos.glm.GLM.score): Validates input and assesses the Poisson GLM using either log-likelihood or pseudo-$R^2$. This method uses the `observation_models` to determine log-likelihood or pseudo-$R^2$. +- [`fit`](nemos.glm.GLM.fit): Validates input and aligns the Poisson GLM with spike train data. It leverages the `observation_models` and `regularizer` to define the model's loss function and instantiate the regularizer. +- [`simulate`](nemos.glm.GLM.simulate): Simulates spike trains using the GLM as a feedforward network, invoking the `observation_models.sample_generator` method for emission probability. +- [`initialize_params`](nemos.glm.GLM.initialize_params): Initialize model parameters, setting to zero the coefficients, and setting the intercept by matching the firing rate. +- [`initialize_state`](nemos.glm.GLM.initialize_state): Initialize the state of the solver. +- [`update`](nemos.glm.GLM.update): Run a step of optimization and update the parameter and solver step. ### Private Methods @@ -61,20 +62,20 @@ Here we list the private method related to the model computations: - **`_predict`**: Forecasts rates based on current model parameters and the inverse-link function of the `observation_models`. - **`_predict_and_compute_loss`**: Predicts the rate and calculates the mean Poisson negative log-likelihood, excluding normalization constants. -A number of `GLM` specific private methods are used for checking parameters and inputs, while the methods related for checking the solver-regularizer configurations/instantiation are inherited from `BaseRergessor`. +A number of [`GLM`](nemos.glm.GLM) specific private methods are used for checking parameters and inputs, while the methods related for checking the solver-regularizer configurations/instantiation are inherited from `BaseRergessor`. ## The Concrete Class `PopulationGLM` -The `PopulationGLM` class is an extension of the `GLM`, designed to fit multiple neurons jointly. This involves vectorized fitting processes that efficiently handle multiple neurons simultaneously, leveraging the inherent parallelism. +The [`PopulationGLM`](nemos.glm.PopulationGLM) class is an extension of the [`GLM`](nemos.glm.GLM), designed to fit multiple neurons jointly. This involves vectorized fitting processes that efficiently handle multiple neurons simultaneously, leveraging the inherent parallelism. ### `PopulationGLM` Specific Attributes -- **`feature_mask`**: A mask that determines which features are used as predictors for each neuron. It can be a matrix of shape `(num_features, num_neurons)` or a `FeaturePytree` of binary values, where 1 indicates that a feature is used for a particular neuron and 0 indicates it is not. +- **`feature_mask`**: A mask that determines which features are used as predictors for each neuron. It can be a matrix of shape `(num_features, num_neurons)` or a [`FeaturePytree`](nemos.pytrees.FeaturePytree) of binary values, where 1 indicates that a feature is used for a particular neuron and 0 indicates it is not. ### Overridden Methods -- **`fit`**: Overridden to handle fitting of the model to a neural population. This method validates input including the mask and fits the model parameters (coefficients and intercepts) to the data. +- [`fit`](nemos.glm.PopulationGLM.fit): Overridden to handle fitting of the model to a neural population. This method validates input including the mask and fits the model parameters (coefficients and intercepts) to the data. - **`_predict`**: Computes the predicted firing rates using the model parameters and the feature mask. @@ -85,9 +86,9 @@ The `PopulationGLM` class is an extension of the `GLM`, designed to fit multiple When crafting a functional (i.e., concrete) GLM class: -- You **must** inherit from `GLM` or one of its derivatives. +- You **must** inherit from [`GLM`](nemos.glm.GLM) or one of its derivatives. - If you inherit directly from `BaseRegressor`, you **must** implement all the abstract methods, see the [`BaseRegressor` page](02-base_regressor.md) for more details. -- If you inherit `GLM` or any of the other concrete classes directly, there won't be any abstract methods. +- If you inherit [`GLM`](nemos.glm.GLM) or any of the other concrete classes directly, there won't be any abstract methods. - You **may** embed additional parameter and input checks if required by the specific GLM subclass. - You **may** override some of the computations if needed by the model specifications. diff --git a/docs/developers_notes/05-observation_models.md b/docs/developers_notes/05-observation_models.md index 9b5e9173..866c7600 100644 --- a/docs/developers_notes/05-observation_models.md +++ b/docs/developers_notes/05-observation_models.md @@ -6,6 +6,7 @@ The `observation_models` module provides objects representing the observations o The abstract class `Observations` defines the structure of the subclasses which specify observation types, such as Poisson, Gamma, etc. These objects serve as attributes of the [`nemos.glm.GLM`](../03-glm/#the-concrete-class-glm) class, equipping the GLM with a negative log-likelihood. This is used to define the optimization objective, the deviance which measures model fit quality, and the emission of new observations, for simulating new data. +(the-abstract-class-observations)= ## The Abstract class `Observations` The abstract class `Observations` is the backbone of any observation model. Any class inheriting `Observations` must reimplement the `_negative_log_likelihood`, `log_likelihood`, `sample_generator`, `deviance`, and `estimate_scale` methods. diff --git a/docs/developers_notes/06-regularizer.md b/docs/developers_notes/06-regularizer.md index 54b19afc..6d09579b 100644 --- a/docs/developers_notes/06-regularizer.md +++ b/docs/developers_notes/06-regularizer.md @@ -23,6 +23,7 @@ Abstract Class Regularizer !!! note If we need advanced adaptive solvers (e.g., Adam, LAMB etc.) in the future, we should consider adding [`Optax`](https://optax.readthedocs.io/en/latest/) as a dependency, which is compatible with `jaxopt`, see [here](https://jaxopt.github.io/stable/_autosummary/jaxopt.OptaxSolver.html#jaxopt.OptaxSolver). +(the-abstract-class-regularizer)= ## The Abstract Class `Regularizer` The abstract class `Regularizer` enforces the implementation of the `penalized_loss` and `get_proximal_operator` methods. diff --git a/docs/developers_notes/README.md b/docs/developers_notes/README.md index 429775e5..9fd92353 100644 --- a/docs/developers_notes/README.md +++ b/docs/developers_notes/README.md @@ -1,4 +1,18 @@ -# Introduction + +## Contents + +```{toctree} +:maxdepth: 1 + +01-base_class.md +02-base_regressor.md +03-glm.md +04-basis_module.md +05-observation_models.md +06-regularizer.md +``` + +## Introduction Welcome to the Developer Notes of the NeMoS project. These notes aim to provide detailed technical information about the various modules, classes, and functions that make up this library, as well as guidelines on how to write code that integrates nicely with our package. They are intended to help current and future developers understand the design decisions, structure, and functioning of the library, and to provide guidance on how to modify, extend, and maintain the codebase. From b28db1d5bef4c5635bbcda84b3f0ad93b89b1d07 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 15 Nov 2024 18:01:27 -0500 Subject: [PATCH 032/107] edited obs models --- docs/api_reference.rst | 1 + docs/developers_notes/04-basis_module.md | 37 ++++++++++--------- .../developers_notes/05-observation_models.md | 32 +++++++++------- 3 files changed, 39 insertions(+), 31 deletions(-) diff --git a/docs/api_reference.rst b/docs/api_reference.rst index 95f7bfb9..ad03e56b 100644 --- a/docs/api_reference.rst +++ b/docs/api_reference.rst @@ -3,6 +3,7 @@ API Reference ============= +.. _nemos_glm: The ``nemos.glm`` module ------------------------ Classes for creating Generalized Linear Models (GLMs) for both single neurons and neural populations. diff --git a/docs/developers_notes/04-basis_module.md b/docs/developers_notes/04-basis_module.md index d834048d..57f75e10 100644 --- a/docs/developers_notes/04-basis_module.md +++ b/docs/developers_notes/04-basis_module.md @@ -2,7 +2,7 @@ ## Introduction -The `nemos.basis` module provides objects that allow users to construct and evaluate basis functions of various types. The classes are hierarchically organized as follows: +The [`nemos.basis`](nemos_basis) module provides objects that allow users to construct and evaluate basis functions of various types. The classes are hierarchically organized as follows: ``` Abstract Class Basis @@ -26,44 +26,47 @@ Abstract Class Basis └─ Concrete Subclass OrthExponentialBasis ``` -The super-class `Basis` provides two public methods, [`compute_features`](#the-public-method-compute_features) and [`evaluate_on_grid`](#the-public-method-evaluate_on_grid). These methods perform checks on both the input provided by the user and the output of the evaluation to ensure correctness, and are thus considered "safe". They both make use of the abstract method `__call__` that is specific for each concrete class. See below for more details. +The super-class [`Basis`](nemos.basis.Basis) provides two public methods, [`compute_features`](#the-public-method-compute_features) and [`evaluate_on_grid`](#the-public-method-evaluate_on_grid). These methods perform checks on both the input provided by the user and the output of the evaluation to ensure correctness, and are thus considered "safe". They both make use of the abstract method [`__call__`](nemos.basis.Basis.__call__) that is specific for each concrete class. See below for more details. ## The Class `nemos.basis.Basis` ### The Public Method `compute_features` -The `compute_features` method checks input consistency and applies the basis function to the inputs. -`Basis` can operate in two modes defined at initialization: `"eval"` and `"conv"`. When a basis is in mode `"eval"`, -`compute_features` evaluates the basis at the given input samples. When in mode `"conv"`, it will convolve the samples +The [`compute_features`](nemos.basis.Basis.compute_features) method checks input consistency and applies the basis function to the inputs. +[`Basis`](nemos.basis.Basis) can operate in two modes defined at initialization: `"eval"` and `"conv"`. When a basis is in mode `"eval"`, +[`compute_features`](nemos.basis.Basis.compute_features) evaluates the basis at the given input samples. When in mode `"conv"`, it will convolve the samples with a bank of kernels, one per basis function. It accepts one or more NumPy array or pynapple `Tsd` object as input, and performs the following steps: 1. Checks that the inputs all have the same sample size `M`, and raises a `ValueError` if this is not the case. 2. Checks that the number of inputs matches what the basis being evaluated expects (e.g., one input for a 1-D basis, N inputs for an N-D basis, or the sum of N 1-D bases), and raises a `ValueError` if this is not the case. -3. In `"eval"` mode, calls the `__call__` method on the input, which is the subclass-specific implementation of the basis set evaluation. In `"conv"` mode, generates a filter bank using `evaluate_on_grid` and then applies the convolution to the input with `nemos.convolve.create_convolutional_predictor`. +3. In `"eval"` mode, calls the `__call__` method on the input, which is the subclass-specific implementation of the basis set evaluation. In `"conv"` mode, generates a filter bank using [`compute_features`](nemos.basis.Basis.evaluate_on_grid) and then applies the convolution to the input with [`nemos.convolve.create_convolutional_predictor`](nemos.convolve.create_convolutional_predictor). 4. Returns a NumPy array or pynapple `TsdFrame` of shape `(M, n_basis_funcs)`, with each basis element evaluated at the samples. -!!! note "Multiple epochs" - Note that the convolution works gracefully with multiple disjoint epochs, when a pynapple time series is used as - input. +:::{admonition} Multiple epochs +:class: note + +Note that the convolution works gracefully with multiple disjoint epochs, when a pynapple time series is used as +input. +::: ### The Public Method `evaluate_on_grid` -The `evaluate_on_grid` method evaluates the basis set on a grid of equidistant sample points. The user specifies the input as a series of integers, one for each dimension of the basis function, that indicate the number of sample points in each coordinate of the grid. +The [`compute_features`](nemos.basis.Basis.evaluate_on_grid) method evaluates the basis set on a grid of equidistant sample points. The user specifies the input as a series of integers, one for each dimension of the basis function, that indicate the number of sample points in each coordinate of the grid. This method performs the following steps: 1. Checks that the number of inputs matches what the basis being evaluated expects (e.g., one input for a 1-D basis, N inputs for an N-D basis, or the sum of N 1-D bases), and raises a `ValueError` if this is not the case. 2. Calls `_get_samples` method, which returns equidistant samples over the domain of the basis function. The domain may depend on the type of basis. -3. Calls the `__call__` method. +3. Calls the [`__call__`](nemos.basis.Basis.__call__) method. 4. Returns both the sample grid points of shape `(m1, ..., mN)`, and the evaluation output at each grid point of shape `(m1, ..., mN, n_basis_funcs)`, where `mi` is the number of sample points for the i-th axis of the grid. ### Abstract Methods -The `nemos.basis.Basis` class has the following abstract methods, which every concrete subclass must implement: +The [`nemos.basis.Basis`](nemos.basis.Basis) class has the following abstract methods, which every concrete subclass must implement: -1. `__call__`: Evaluates a basis over some specified samples. +1. [`__call__`](nemos.basis.Basis.__call__): Evaluates a basis over some specified samples. 2. `_check_n_basis_min`: Checks the minimum number of basis functions required. This requirement can be specific to the type of basis. ## Contributors Guidelines @@ -71,8 +74,8 @@ The `nemos.basis.Basis` class has the following abstract methods, which every co ### Implementing Concrete Basis Objects To write a usable (i.e., concrete, non-abstract) basis object, you -- **Must** inherit the abstract superclass `Basis` -- **Must** define the `__call__` and `_check_n_basis_min` methods with the expected input/output format, see [API Guide](../../reference/nemos/basis/) for the specifics. -- **Should not** overwrite the `compute_features` and `evaluate_on_grid` methods inherited from `Basis`. -- **May** inherit any number of abstract intermediate classes (e.g., `SplineBasis`). +- **Must** inherit the abstract superclass [`Basis`](nemos.basis.Basis) +- **Must** define the [`__call__`](nemos.basis.Basis.__call__) and `_check_n_basis_min` methods with the expected input/output format, see [API Reference](basis_nemos) for the specifics. +- **Should not** overwrite the [`compute_features`](nemos.basis.Basis.compute_features) and [`compute_features`](nemos.basis.Basis.evaluate_on_grid) methods inherited from [`Basis`](nemos.basis.Basis). +- **May** inherit any number of abstract intermediate classes (e.g., [`SplineBasis`](nemos.basis.SplineBasis)). diff --git a/docs/developers_notes/05-observation_models.md b/docs/developers_notes/05-observation_models.md index 866c7600..0573c6eb 100644 --- a/docs/developers_notes/05-observation_models.md +++ b/docs/developers_notes/05-observation_models.md @@ -2,46 +2,50 @@ ## Introduction -The `observation_models` module provides objects representing the observations of GLM-like models. +The [`observation_models`](observation_models) module provides objects representing the observations of GLM-like models. -The abstract class `Observations` defines the structure of the subclasses which specify observation types, such as Poisson, Gamma, etc. These objects serve as attributes of the [`nemos.glm.GLM`](../03-glm/#the-concrete-class-glm) class, equipping the GLM with a negative log-likelihood. This is used to define the optimization objective, the deviance which measures model fit quality, and the emission of new observations, for simulating new data. +The abstract class [`Observations`](nemos.observation_models.Observations) defines the structure of the subclasses which specify observation types, such as Poisson, Gamma, etc. These objects serve as attributes of the [`nemos.glm.GLM`](the-concrete-class-glm) class, equipping the GLM with a negative log-likelihood. This is used to define the optimization objective, the deviance which measures model fit quality, and the emission of new observations, for simulating new data. (the-abstract-class-observations)= ## The Abstract class `Observations` -The abstract class `Observations` is the backbone of any observation model. Any class inheriting `Observations` must reimplement the `_negative_log_likelihood`, `log_likelihood`, `sample_generator`, `deviance`, and `estimate_scale` methods. +The abstract class [`Observations`](nemos.observation_models.Observations) is the backbone of any observation model. Any class inheriting [`Observations`](nemos.observation_models.Observations) must reimplement the `_negative_log_likelihood`, [`log_likelihood`](nemos.observation_models.Observations.log_likelihood), [`sample_generator`](nemos.observation_models.Observations.sample_generator), [`deviance`](nemos.observation_models.Observations.deviance), and [`estimate_scale`](nemos.observation_models.Observations.estimate_scale) methods. ### Abstract Methods -For subclasses derived from `Observations` to function correctly, they must implement the following: +For subclasses derived from [`Observations`](nemos.observation_models.Observations) to function correctly, they must implement the following: - **_negative_log_likelihood**: Computes the negative-log likelihood of the model up to a normalization constant. This method is usually part of the objective function used to learn GLM parameters. -- **log_likelihood**: Computes the full log-likelihood including the normalization constant. +- [`log_likelihood`](nemos.observation_models.Observations.log_likelihood): Computes the full log-likelihood including the normalization constant. -- **sample_generator**: Returns the random emission probability function. This typically invokes `jax.random` emission probability, provided some sufficient statistics, [see below](#suff-stat). For distributions in the exponential family, the sufficient statistics are the canonical parameter and the scale. In GLMs, the canonical parameter is entirely specified by the model's weights, while the scale is either fixed (i.e., Poisson) or needs to be estimated (i.e., Gamma). +- [`sample_generator`](nemos.observation_models.Observations.sample_generator): Returns the random emission probability function. This typically invokes `jax.random` emission probability, provided some sufficient statistics, [see below](#suff-stat). For distributions in the exponential family, the sufficient statistics are the canonical parameter and the scale. In GLMs, the canonical parameter is entirely specified by the model's weights, while the scale is either fixed (i.e., Poisson) or needs to be estimated (i.e., Gamma). -- **deviance**: Computes the deviance based on the model's estimated rates and observations. +- [`deviance`](nemos.observation_models.Observations.deviance): Computes the deviance based on the model's estimated rates and observations. -- **estimate_scale**: A method for estimating the scale parameter of the model. Rate and scale are sufficient to fully characterize distributions from the exponential family. +- [`estimate_scale`](nemos.observation_models.Observations.estimate_scale): A method for estimating the scale parameter of the model. Rate and scale are sufficient to fully characterize distributions from the exponential family. -???+ info "Sufficient statistics" - In statistics, a statistic is sufficient with respect to a statistical model and its associated unknown parameters if "no other statistic that can be calculated from the same sample provides any additional information as to the value of the parameters", adapted from [[1]](#ref-1). +:::{dropdown} Sufficient statistics +:color: info +:icon: info + +In statistics, a statistic is sufficient with respect to a statistical model and its associated unknown parameters if "no other statistic that can be calculated from the same sample provides any additional information as to the value of the parameters", adapted from [[1]](#ref-1). +::: ### Public Methods -- **pseudo_r2**: Method for computing the pseudo-$R^2$ of the model based on the residual deviance. There is no consensus definition for the pseudo-$R^2$, what we used here is the definition by Cohen at al. 2003[$^{[2]}$](#ref-2). -- **check_inverse_link_function**: Check that the link function is a auto-differentiable, vectorized function form $\mathbb{R} \longrightarrow \mathbb{R}$. +- [`pseudo_r2`](nemos.observation_models.Observations.pseudo_r2): Method for computing the pseudo-$R^2$ of the model based on the residual deviance. There is no consensus definition for the pseudo-$R^2$, what we used here is the definition by Cohen at al. 2003[$^{[2]}$](#ref-2). +- [`check_inverse_link_function`](nemos.observation_models.Observations.check_inverse_link_function): Check that the link function is a auto-differentiable, vectorized function form $\mathbb{R} \longrightarrow \mathbb{R}$. ## Contributor Guidelines To implement an observation model class you -- **Must** inherit from `Observations` +- **Must** inherit from [`Observations`](nemos.observation_models.Observations) - **Must** provide a concrete implementation of the abstract methods, see above. -- **Should not** reimplement the `pseudo_r2` method as well as the `check_inverse_link_function` auxiliary method. +- **Should not** reimplement the [`pseudo_r2`](nemos.observation_models.Observations.pseudo_r2) method as well as the [`check_inverse_link_function`](nemos.observation_models.Observations.check_inverse_link_function) auxiliary method. ## References

[1] From b6d0da4debdea8f6798f78f563d9b297b02b3463 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 15 Nov 2024 18:16:19 -0500 Subject: [PATCH 033/107] finished dev notes --- docs/developers_notes/03-glm.md | 2 +- docs/developers_notes/06-regularizer.md | 56 +++++++++++++------------ 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/docs/developers_notes/03-glm.md b/docs/developers_notes/03-glm.md index 29e2915d..1d69303d 100644 --- a/docs/developers_notes/03-glm.md +++ b/docs/developers_notes/03-glm.md @@ -24,7 +24,7 @@ Instantiating a specific GLM simply requires providing an observation model (Gam - +(the-concrete-class-glm)= ## The Concrete Class `GLM` The [`GLM`](nemos.glm.GLM) class provides a direct implementation of the GLM model and is designed with `scikit-learn` compatibility in mind. diff --git a/docs/developers_notes/06-regularizer.md b/docs/developers_notes/06-regularizer.md index 6d09579b..bfb049b7 100644 --- a/docs/developers_notes/06-regularizer.md +++ b/docs/developers_notes/06-regularizer.md @@ -2,11 +2,11 @@ ## Introduction -The `regularizer` module introduces an archetype class `Regularizer` which provides the structural components for each concrete sub-class. +The [`regularizer`](regularizers) module introduces an archetype class [`Regularizer`](nemos.regularizer.Regularizer) which provides the structural components for each concrete sub-class. -Objects of type `Regularizer` provide methods to define a regularized optimization objective. These objects serve as attribute of the [`nemos.glm.GLM`](../03-glm/#the-concrete-class-glm), equipping the glm with an appropriate regularization scheme. +Objects of type [`Regularizer`](nemos.regularizer.Regularizer) provide methods to define a regularized optimization objective. These objects serve as attribute of the [`nemos.glm.GLM`](the-concrete-class-glm), equipping the glm with an appropriate regularization scheme. -Each `Regularizer` object defines a default solver, and a set of allowed solvers, which depends on the loss function characteristics (smooth vs non-smooth). +Each [`Regularizer`](nemos.regularizer.Regularizer) object defines a default solver, and a set of allowed solvers, which depends on the loss function characteristics (smooth vs non-smooth). ``` Abstract Class Regularizer @@ -20,31 +20,32 @@ Abstract Class Regularizer └─ Concrete Class GroupLasso ``` -!!! note - If we need advanced adaptive solvers (e.g., Adam, LAMB etc.) in the future, we should consider adding [`Optax`](https://optax.readthedocs.io/en/latest/) as a dependency, which is compatible with `jaxopt`, see [here](https://jaxopt.github.io/stable/_autosummary/jaxopt.OptaxSolver.html#jaxopt.OptaxSolver). +:::{note} +If we need advanced adaptive solvers (e.g., Adam, LAMB etc.) in the future, we should consider adding [`Optax`](https://optax.readthedocs.io/en/latest/) as a dependency, which is compatible with `jaxopt`, see [here](https://jaxopt.github.io/stable/_autosummary/jaxopt.OptaxSolver.html#jaxopt.OptaxSolver). +::: (the-abstract-class-regularizer)= ## The Abstract Class `Regularizer` -The abstract class `Regularizer` enforces the implementation of the `penalized_loss` and `get_proximal_operator` methods. +The abstract class [`Regularizer`](nemos.regularizer.Regularizer) enforces the implementation of the [`penalized_loss`](nemos.regularizer.Regularizer.penalized_loss) and [`get_proximal_operator`](nemos.regularizer.Regularizer.get_proximal_operator) methods. ### Attributes -The attributes of `Regularizer` consist of the `default_solver` and `allowed_solvers`, which are stored as read-only properties of type string and tuple of strings respectively. +The attributes of [`Regularizer`](nemos.regularizer.Regularizer) consist of the `default_solver` and `allowed_solvers`, which are stored as read-only properties of type string and tuple of strings respectively. ### Abstract Methods -- **`penalized_loss`**: Returns a penalized version of the input loss function which is uniquely defined by the regularization scheme and the regularizer strength parameter. -- **`get_proximal_operator`**: Returns the proximal projection operator which is uniquely defined by the regularization scheme. +- [`penalized_loss`](nemos.regularizer.Regularizer.penalized_loss): Returns a penalized version of the input loss function which is uniquely defined by the regularization scheme and the regularizer strength parameter. +- [`get_proximal_operator`](nemos.regularizer.Regularizer.get_proximal_operator): Returns the proximal projection operator which is uniquely defined by the regularization scheme. ## The `UnRegularized` Class -The `UnRegularized` class extends the base `Regularizer` class and is designed specifically for optimizing unregularized models. This means that the solver instantiated by this class does not add any regularization penalty to the loss function during the optimization process. +The [`UnRegularized`](nemos.regularizer.UnRegularized) class extends the base [`Regularizer`](nemos.regularizer.Regularizer) class and is designed specifically for optimizing unregularized models. This means that the solver instantiated by this class does not add any regularization penalty to the loss function during the optimization process. ### Concrete Methods Specifics -- **`penalized_loss`**: Returns the original loss without any changes. -- **`get_proximal_operator`**: Returns the identity operator. +- [`penalized_loss`](nemos.regularizer.UnRegularized.penalized_loss): Returns the original loss without any changes. +- [`get_proximal_operator`](nemos.regularizer.UnRegularized.get_proximal_operator): Returns the identity operator. ## Contributor Guidelines @@ -53,18 +54,21 @@ The `UnRegularized` class extends the base `Regularizer` class and is designed s When developing a functional (i.e., concrete) `Regularizer` class: -- **Must** inherit from `Regularizer` or one of its derivatives. -- **Must** implement the `penalized_loss` and `get_proximal_operator` methods. +- **Must** inherit from [`Regularizer`](nemos.regularizer.Regularizer) or one of its derivatives. +- **Must** implement the [`penalized_loss`](nemos.regularizer.Regularizer.penalized_loss) and [`get_proximal_operator`](nemos.regularizer.Regularizer.get_proximal_operator) methods. - **Must** define a default solver and a tuple of allowed solvers. -- **May** require extra initialization parameters, like the `mask` argument of `GroupLasso`. - -??? tip "Convergence Test" - When adding a new regularizer, you must include a convergence test, which verifies that - the model parameters the regularizer finds for a convex problem such as the GLM are identical - whether one minimizes the penalized loss directly and uses the proximal operator (i.e., when - using `ProximalGradient`). In practice, this means you should test the result of the `ProximalGradient` - optimization against that of either `GradientDescent` (if your regularization is differentiable) or - `Nelder-Mead` from [`scipy.optimize.minimize`](https://docs.scipy.org/doc/scipy/reference/optimize.minimize-neldermead.html) - (or another non-gradient based method, if your regularization is non-differentiable). You can refer to NeMoS `test_lasso_convergence` - from `tests/test_convergence.py` for a concrete example. - +- **May** require extra initialization parameters, like the `mask` argument of [`GroupLasso`](nemos.regularizer.GroupLasso). + +:::{dropdown} Convergence Test +:icon: light-bulb +:color: success + +When adding a new regularizer, you must include a convergence test, which verifies that +the model parameters the regularizer finds for a convex problem such as the GLM are identical +whether one minimizes the penalized loss directly and uses the proximal operator (i.e., when +using `ProximalGradient`). In practice, this means you should test the result of the `ProximalGradient` +optimization against that of either `GradientDescent` (if your regularization is differentiable) or +`Nelder-Mead` from [`scipy.optimize.minimize`](https://docs.scipy.org/doc/scipy/reference/optimize.minimize-neldermead.html) +(or another non-gradient based method, if your regularization is non-differentiable). You can refer to NeMoS `test_lasso_convergence` +from `tests/test_convergence.py` for a concrete example. +::: \ No newline at end of file From 497e374c4e5321beb8f8cefd93489760a294d435 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Sat, 16 Nov 2024 00:23:10 -0500 Subject: [PATCH 034/107] fixing some links --- docs/api_reference.rst | 2 +- docs/{ => assets}/head_dir_tuning.jpg | Bin docs/how_to_guide/plot_03_population_glm.md | 2 +- .../plot_05_sklearn_pipeline_cv_demo.md | 2 +- docs/index.md | 6 +++--- docs/quickstart.md | 12 ++++++------ docs/tutorials/plot_01_current_injection.md | 4 ++-- docs/tutorials/plot_06_calcium_imaging.md | 2 +- src/nemos/basis.py | 2 +- src/nemos/simulation.py | 4 ++-- 10 files changed, 18 insertions(+), 18 deletions(-) rename docs/{ => assets}/head_dir_tuning.jpg (100%) diff --git a/docs/api_reference.rst b/docs/api_reference.rst index ad03e56b..119e7824 100644 --- a/docs/api_reference.rst +++ b/docs/api_reference.rst @@ -82,7 +82,7 @@ Utility functions for simulating spiking activity in recurrently connected neura .. currentmodule:: nemos.simulation .. autosummary:: - :toctree: generated/regularizer + :toctree: generated/simulation :recursive: :nosignatures: diff --git a/docs/head_dir_tuning.jpg b/docs/assets/head_dir_tuning.jpg similarity index 100% rename from docs/head_dir_tuning.jpg rename to docs/assets/head_dir_tuning.jpg diff --git a/docs/how_to_guide/plot_03_population_glm.md b/docs/how_to_guide/plot_03_population_glm.md index 07c90bb6..41c609e7 100644 --- a/docs/how_to_guide/plot_03_population_glm.md +++ b/docs/how_to_guide/plot_03_population_glm.md @@ -33,7 +33,7 @@ memory efficient, the latter is computationally more efficient (it takes less ti NeMoS has a dedicated [`nemos.GLM.PopulationGLM`](nemos.glm.PopulationGLM) class for fitting jointly a neural population. The API is very similar to that the regular [`GLM`](nemos.glm.GLM), but with a few differences: - 1. The `y` input to the methods [`fit`](nemos.glm.PopulationGLM.fit) and [`score`](nemos.GLM.PopulationGLM.score) must be a two-dimensional array of shape `(n_samples, n_neurons)`. + 1. The `y` input to the methods [`fit`](nemos.glm.PopulationGLM.fit) and [`score`](nemos.glm.PopulationGLM.score) must be a two-dimensional array of shape `(n_samples, n_neurons)`. 2. You can optionally pass a `feature_mask` in the form of an array of 0s and 1s with shape `(n_features, n_neurons)` that specifies which features are used as predictors for each neuron. More on this [later](#neuron-specific-features). diff --git a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md index 6aa7df5b..b37b5d8b 100644 --- a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md +++ b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md @@ -15,7 +15,7 @@ kernelspec: %matplotlib inline ``` - +(sklearn-how-to)= # Selecting basis by cross-validation with scikit-learn In this demo, we will demonstrate how to select an appropriate basis and its hyperparameters using cross-validation. diff --git a/docs/index.md b/docs/index.md index 6660cd06..c409e981 100644 --- a/docs/index.md +++ b/docs/index.md @@ -102,9 +102,9 @@ Explore fully worked examples to learn how to analyze neural recordings from scr ::: -:::{grid-item-card}   **API Guide** -:link: api_guide.html -:link-alt: API Guide +:::{grid-item-card}   **API Reference** +:link: api_reference.html +:link-alt: API Reference --- diff --git a/docs/quickstart.md b/docs/quickstart.md index 4507903a..71c82331 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -156,7 +156,7 @@ The `basis` module includes objects that perform two types of transformations on Non-linear mapping is the default mode of operation of any `basis` object. To instantiate a basis for non-linear mapping, -you need to specify the number of basis functions. For some `basis` objects, additional arguments may be required (see the [API Guide](../reference/nemos/basis) for detailed information). +you need to specify the number of basis functions. For some `basis` objects, additional arguments may be required (see the [API Reference](nemos_basis) for detailed information). ```python @@ -237,12 +237,12 @@ The `window_size` must be shorter than the number of samples in the signal(s) be ``` -For additional information on one-dimensional convolutions, see [here](../generated/background/plot_03_1D_convolution). +For additional information on one-dimensional convolutions, see [here](convolution_background). ## **Continuous Observations** -By default, NeMoS' GLM uses [Poisson observations](../reference/nemos/observation_models/#nemos.observation_models.PoissonObservations), which are a natural choice for spike counts. However, the package also supports a [Gamma](../reference/nemos/observation_models/#nemos.observation_models.GammaObservations) GLM, which is more appropriate for modeling continuous, non-negative observations such as calcium transients. +By default, NeMoS' GLM uses [Poisson observations](nemos.observation_models.PoissonObservations), which are a natural choice for spike counts. However, the package also supports a [Gamma](nemos.observation_models.GammaObservations) GLM, which is more appropriate for modeling continuous, non-negative observations such as calcium transients. To change the default observation model, set the `observation_model` argument during initialization: @@ -257,13 +257,13 @@ To change the default observation model, set the `observation_model` argument du ``` -Take a look at our [tutorial](../generated/tutorials/plot_06_calcium_imaging) for a detailed example. +Take a look at our [tutorial](tutorial-calcium-imaging) for a detailed example. ## **Regularization** -NeMoS supports various regularization schemes, including [Ridge](../reference/nemos/regularizer/#nemos.regularizer.Ridge) ($L_2$), [Lasso](../reference/nemos/regularizer/#nemos.regularizer.Lasso) ($L_1$), and [Group Lasso](../reference/nemos/regularizer/#nemos.regularizer.GroupLasso), to prevent overfitting and improve model generalization. +NeMoS supports various regularization schemes, including [Ridge](nemos.regularizer.Ridge) ($L_2$), [Lasso](nemos.regularizer.Lasso) ($L_1$), and [Group Lasso](nemos.regularizer.GroupLasso), to prevent overfitting and improve model generalization. You can specify the regularization scheme and its strength when initializing the GLM model: @@ -433,7 +433,7 @@ Fit a 5-fold cross-validation scheme for comparing two different regularizer str :::{admonition} Cross-Validation in NeMoS :class: info -For more information and a practical example on how to construct a parameter grid and cross-validate hyperparameters across an entire pipeline, please refer to the [tutorial on pipelining and cross-validation](../generated/how_to_guide/plot_06_sklearn_pipeline_cv_demo). +For more information and a practical example on how to construct a parameter grid and cross-validate hyperparameters across an entire pipeline, please refer to the [tutorial on pipelining and cross-validation](sklearn-how-to). ::: Finally, we can print the regularizer strength with the best cross-validated performance: diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md index 617ac03e..9f872f74 100644 --- a/docs/tutorials/plot_01_current_injection.md +++ b/docs/tutorials/plot_01_current_injection.md @@ -474,7 +474,7 @@ of the existing dimensions? In NeMoS, we always fit Generalized Linear Models to a single neuron at a time. We'll discuss this more in the [following -tutorial](../plot_02_head_direction/), but briefly: you get the same answer +tutorial](plot_02_head_direction.md), but briefly: you get the same answer whether you fit the neurons separately or simultaneously, and fitting them separately can make your life easier. ::: @@ -516,7 +516,7 @@ different results.) data (in this case spikes), describing the distribution of neural activity (and thus changing the log-likelihood). For spiking data, we use the Poisson observation model, but we discuss other options for continuous data - in [the calcium imaging analysis demo](../plot_06_calcium_imaging/). + in [the calcium imaging analysis demo](plot_06_calcium_imaging.md). For this example, we'll use an un-regularized LBFGS solver. We'll discuss regularization in a later tutorial. diff --git a/docs/tutorials/plot_06_calcium_imaging.md b/docs/tutorials/plot_06_calcium_imaging.md index 632abfeb..fb896c5a 100644 --- a/docs/tutorials/plot_06_calcium_imaging.md +++ b/docs/tutorials/plot_06_calcium_imaging.md @@ -15,7 +15,7 @@ kernelspec: %matplotlib inline ``` - +(tutorial-calcium-imaging)= Fit Calcium Imaging ============ diff --git a/src/nemos/basis.py b/src/nemos/basis.py index 0df1a5f9..a32855b8 100644 --- a/src/nemos/basis.py +++ b/src/nemos/basis.py @@ -629,7 +629,7 @@ def label(self) -> str: def n_basis_input(self) -> tuple | None: """Number of expected inputs. - The number of inputs `compute_feature expects. + The number of inputs ``compute_feature`` expects. """ if self._n_basis_input is None: return diff --git a/src/nemos/simulation.py b/src/nemos/simulation.py index 3f0ddd25..b750d454 100644 --- a/src/nemos/simulation.py +++ b/src/nemos/simulation.py @@ -48,7 +48,7 @@ def difference_of_gammas( p(x;\; a, b) = \frac{b^a x^{a-1} e^{-x}}{\Gamma(a)}, - where :math:`\Gamma(a)` refers to the gamma function, see [[1]](#references). + where :math:`\Gamma(a)` refers to the gamma function, see [1]_. Returns ------- @@ -63,7 +63,7 @@ def difference_of_gammas( References ---------- - SciPy Docs - :meth:`scipy.stats.gamma ` + .. [1] SciPy Docs - :meth:`scipy.stats.gamma ` Examples -------- From 96d04a5b0baea10372dbcfdb553087dd2c4978cd Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Sat, 16 Nov 2024 00:52:13 -0500 Subject: [PATCH 035/107] fixed all links --- .readthedocs.yaml | 4 +--- docs/api_reference.rst | 1 + docs/background/plot_01_1D_basis_function.md | 2 +- docs/developers_notes/03-glm.md | 6 +++--- docs/developers_notes/04-basis_module.md | 8 +++++--- src/nemos/basis.py | 8 ++++---- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index b1e575be..1e68ab4e 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -15,9 +15,7 @@ build: - gem install html-proofer -v ">= 5.0.9" # Ensure version >= 5.0.9 post_build: # Check everything but the reference (because mkdocstrings do not set href=) - - htmlproofer $READTHEDOCS_OUTPUT/html --checks Links,Scripts --ignore-urls "https://fonts.gstatic.com,https://www.jneurosci.org/content/25/47/11003" --assume-extension --check-external-hash --ignore-status-codes 403 --ignore-files "/.+\/html\/reference\/.+/" - # Check the reference allowing missing href - - htmlproofer $READTHEDOCS_OUTPUT/html/reference --assume-extension --check-external-hash --ignore-urls "https://fonts.gstatic.com" --allow-missing-href --ignore-status-codes 403 + - htmlproofer $READTHEDOCS_OUTPUT/_build/html/ --checks Links,Scripts --ignore-urls "https://fonts.gstatic.com,https://www.jneurosci.org/content/25/47/11003" --assume-extension --check-external-hash --ignore-status-codes 403 --ignore-files "/.+\/_static\/.+/","/.+\/stubs\/.+/" mkdocs: configuration: mkdocs.yml diff --git a/docs/api_reference.rst b/docs/api_reference.rst index 119e7824..779e31a6 100644 --- a/docs/api_reference.rst +++ b/docs/api_reference.rst @@ -31,6 +31,7 @@ Provides basis function classes to construct and transform features for model in :nosignatures: Basis + SplineBasis BSplineBasis CyclicBSplineBasis MSplineBasis diff --git a/docs/background/plot_01_1D_basis_function.md b/docs/background/plot_01_1D_basis_function.md index d8801fde..b34f06e9 100644 --- a/docs/background/plot_01_1D_basis_function.md +++ b/docs/background/plot_01_1D_basis_function.md @@ -93,7 +93,7 @@ plt.tight_layout() ``` ## Basis `mode` -In constructing features, [`Basis`](nemos.basis.basis) objects can be used in two modalities: `"eval"` for evaluate or `"conv"` +In constructing features, [`Basis`](nemos.basis.Basis) objects can be used in two modalities: `"eval"` for evaluate or `"conv"` for convolve. These two modalities change the behavior of the [`compute_features`](nemos.basis.Basis.compute_features) method of [`Basis`](nemos.basis.Basis), in particular, - If a basis is in mode `"eval"`, then [`compute_features`](nemos.basis.Basis.compute_features) simply returns the evaluated basis. diff --git a/docs/developers_notes/03-glm.md b/docs/developers_notes/03-glm.md index 1d69303d..366c08ce 100644 --- a/docs/developers_notes/03-glm.md +++ b/docs/developers_notes/03-glm.md @@ -15,7 +15,7 @@ Our design aligns with the `scikit-learn` API, facilitating seamless integration The classes provided here are modular by design offering a standard foundation for any GLM variant. -Instantiating a specific GLM simply requires providing an observation model (Gamma, Poisson, etc.), a regularization strategies (Ridge, Lasso, etc.) and an optimization scheme during initialization. This is done using the [`nemos.observation_models.Observations`](the-abstract-class-observations), [`nemos.regularizer.Regularizer`](the-abstract-class-regularizer) objects as well as the compatible `jaxopt` solvers, respectively. +Instantiating a specific GLM simply requires providing an observation model (Gamma, Poisson, etc.), a regularization strategies (Ridge, Lasso, etc.) and an optimization scheme during initialization. This is done using the [`nemos.observation_models.Observations`](nemos.observation_models.Observations), [`nemos.regularizer.Regularizer`](nemos.regularizer.Regularizer) objects as well as the compatible `jaxopt` solvers, respectively.

@@ -31,12 +31,12 @@ The [`GLM`](nemos.glm.GLM) class provides a direct implementation of the GLM mod ### Inheritance -[`GLM`](nemos.glm.GLM) inherits from [`BaseRegressor`](../02-base_regressor/#the-abstract-class-baseregressor). This inheritance mandates the direct implementation of methods like [`predict`](nemos.glm.GLM.predict), [`fit`](nemos.glm.GLM.fit), [`score`](nemos.glm.GLM.score), [`update`](nemos.glm.GLM.update), and [`simulate`(nemos.glm.GLM.[`GLM`](nemos.glm.GLM) inherits from [`BaseRegressor`](../02-base_regressor/#the-abstract-class-baseregressor). This inheritance mandates the direct implementation of methods like [`predict`](nemos.glm.GLM.predict), [`fit`](nemos.glm.GLM.fit), [`score`](nemos.glm.GLM.score), [`update`](nemos.glm.GLM.update), and [`simulate`](nemos.glm.GLM.simulate), plus a number of validation methods. +[`GLM`](nemos.glm.GLM) inherits from [`BaseRegressor`](02-base_regressor.md). This inheritance mandates the direct implementation of methods like [`predict`](nemos.glm.GLM.predict), [`fit`](nemos.glm.GLM.fit), [`score`](nemos.glm.GLM.score), [`update`](nemos.glm.GLM.update), and [`simulate`(nemos.glm.GLM.[`GLM`](nemos.glm.GLM) inherits from [`BaseRegressor`](02-base_regressor.md). This inheritance mandates the direct implementation of methods like [`predict`](nemos.glm.GLM.predict), [`fit`](nemos.glm.GLM.fit), [`score`](nemos.glm.GLM.score), [`update`](nemos.glm.GLM.update), and [`simulate`](nemos.glm.GLM.simulate), plus a number of validation methods. ), plus a number of validation methods. ### Attributes -- **`observation_model`**: Property that represents the GLM observation model, which is an object of the [`nemos.observation_models.Observations`](the-abstract-class-observations) type. This model determines the log-likelihood and the emission probability mechanism for the [`GLM`](nemos.glm.GLM). +- **`observation_model`**: Property that represents the GLM observation model, which is an object of the [`nemos.observation_models.Observations`](nemos.observation_models.Observations) type. This model determines the log-likelihood and the emission probability mechanism for the [`GLM`](nemos.glm.GLM). - **`coef_`**: Stores the solution for spike basis coefficients as `jax.ndarray` after the fitting process. It is initialized as `None` during class instantiation. - **`intercept_`**: Stores the bias terms' solutions as `jax.ndarray` after the fitting process. It is initialized as `None` during class instantiation. - **`dof_resid_`**: The degrees of freedom of the model's residual. this quantity is used to estimate the scale parameter, see below, and compute frequentist confidence intervals. diff --git a/docs/developers_notes/04-basis_module.md b/docs/developers_notes/04-basis_module.md index 57f75e10..d0f939a0 100644 --- a/docs/developers_notes/04-basis_module.md +++ b/docs/developers_notes/04-basis_module.md @@ -26,10 +26,11 @@ Abstract Class Basis └─ Concrete Subclass OrthExponentialBasis ``` -The super-class [`Basis`](nemos.basis.Basis) provides two public methods, [`compute_features`](#the-public-method-compute_features) and [`evaluate_on_grid`](#the-public-method-evaluate_on_grid). These methods perform checks on both the input provided by the user and the output of the evaluation to ensure correctness, and are thus considered "safe". They both make use of the abstract method [`__call__`](nemos.basis.Basis.__call__) that is specific for each concrete class. See below for more details. +The super-class [`Basis`](nemos.basis.Basis) provides two public methods, [`compute_features`](the-public-method-compute_features) and [`evaluate_on_grid`](the-public-method-evaluate_on_grid). These methods perform checks on both the input provided by the user and the output of the evaluation to ensure correctness, and are thus considered "safe". They both make use of the abstract method [`__call__`](nemos.basis.Basis.__call__) that is specific for each concrete class. See below for more details. ## The Class `nemos.basis.Basis` +(the-public-method-compute_features)= ### The Public Method `compute_features` The [`compute_features`](nemos.basis.Basis.compute_features) method checks input consistency and applies the basis function to the inputs. @@ -51,9 +52,10 @@ Note that the convolution works gracefully with multiple disjoint epochs, when a input. ::: +(the-public-method-evaluate_on_grid)= ### The Public Method `evaluate_on_grid` -The [`compute_features`](nemos.basis.Basis.evaluate_on_grid) method evaluates the basis set on a grid of equidistant sample points. The user specifies the input as a series of integers, one for each dimension of the basis function, that indicate the number of sample points in each coordinate of the grid. +The [`compute_features`](nemos.basis.Basis.compute_features) method evaluates the basis set on a grid of equidistant sample points. The user specifies the input as a series of integers, one for each dimension of the basis function, that indicate the number of sample points in each coordinate of the grid. This method performs the following steps: @@ -75,7 +77,7 @@ The [`nemos.basis.Basis`](nemos.basis.Basis) class has the following abstract me To write a usable (i.e., concrete, non-abstract) basis object, you - **Must** inherit the abstract superclass [`Basis`](nemos.basis.Basis) -- **Must** define the [`__call__`](nemos.basis.Basis.__call__) and `_check_n_basis_min` methods with the expected input/output format, see [API Reference](basis_nemos) for the specifics. +- **Must** define the [`__call__`](nemos.basis.Basis.__call__) and `_check_n_basis_min` methods with the expected input/output format, see [API Reference](nemos_basis) for the specifics. - **Should not** overwrite the [`compute_features`](nemos.basis.Basis.compute_features) and [`compute_features`](nemos.basis.Basis.evaluate_on_grid) methods inherited from [`Basis`](nemos.basis.Basis). - **May** inherit any number of abstract intermediate classes (e.g., [`SplineBasis`](nemos.basis.SplineBasis)). diff --git a/src/nemos/basis.py b/src/nemos/basis.py index a32855b8..527c6df9 100644 --- a/src/nemos/basis.py +++ b/src/nemos/basis.py @@ -2053,9 +2053,9 @@ def _check_n_basis_min(self) -> None: class MSplineBasis(SplineBasis): r""" - M-spline [1]_ basis functions for modeling and data transformation. + M-spline basis functions for modeling and data transformation. - M-splines are a type of spline basis function used for smooth curve fitting + M-splines [1]_ are a type of spline basis function used for smooth curve fitting and data representation. They are positive and integrate to one, making them suitable for probabilistic models and density estimation. The order of an M-spline defines its smoothness, with higher orders resulting in smoother @@ -2576,7 +2576,7 @@ class RaisedCosineBasisLinear(Basis): .. [1] Pillow, J. W., Paninski, L., Uzzel, V. J., Simoncelli, E. P., & J., C. E. (2005). Prediction and decoding of retinal ganglion cell responses with a probabilistic spiking model. Journal of Neuroscience, 25(47), - 11003–11013. http://dx.doi.org/10.1523/jneurosci.3305-05.2005 + 11003–11013. """ def __init__( @@ -2791,7 +2791,7 @@ class RaisedCosineBasisLog(RaisedCosineBasisLinear): .. [1] Pillow, J. W., Paninski, L., Uzzel, V. J., Simoncelli, E. P., & J., C. E. (2005). Prediction and decoding of retinal ganglion cell responses with a probabilistic spiking model. Journal of Neuroscience, 25(47), - 11003–11013. http://dx.doi.org/10.1523/jneurosci.3305-05.2005 + 11003–11013. """ def __init__( From 883daf400fb5732baaf1c2c8c9d37bd407d54009 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Sat, 16 Nov 2024 11:41:17 -0500 Subject: [PATCH 036/107] added logo flatiron white --- docs/assets/logo_flatiron_white.svg | 206 ++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 docs/assets/logo_flatiron_white.svg diff --git a/docs/assets/logo_flatiron_white.svg b/docs/assets/logo_flatiron_white.svg new file mode 100644 index 00000000..9509e67d --- /dev/null +++ b/docs/assets/logo_flatiron_white.svg @@ -0,0 +1,206 @@ + + + + From c027d80068ccd1b43a222c566a9752206a9878a9 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Sat, 16 Nov 2024 11:41:41 -0500 Subject: [PATCH 037/107] switch logo in mode dark --- docs/index.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index c409e981..87784582 100644 --- a/docs/index.md +++ b/docs/index.md @@ -132,4 +132,14 @@ Open source, [licensed under MIT](https://github.com/flatironinstitute/nemos/blo This package is supported by the Center for Computational Neuroscience, in the Flatiron Institute of the Simons Foundation. -Flatiron Center for Computational Neuroscience logo. +```{image} assets/logo_flatiron_white.svg +:alt: Flatiron Center for Computational Neuroscience logo White. +:class: only-dark +:width: 20% +``` + +```{image} assets/CCN-logo-wText.png +:alt: Flatiron Center for Computational Neuroscience logo. +:class: only-light +:width: 20% +``` From 35428d4fefa6637f19e5c09f089b31fc601e5f50 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Sat, 16 Nov 2024 11:48:01 -0500 Subject: [PATCH 038/107] add target --- docs/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/index.md b/docs/index.md index 87784582..8ac42f9d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -136,10 +136,12 @@ This package is supported by the Center for Computational Neuroscience, in the F :alt: Flatiron Center for Computational Neuroscience logo White. :class: only-dark :width: 20% +:target: https://www.simonsfoundation.org/flatiron/center-for-computational-neuroscience/ ``` ```{image} assets/CCN-logo-wText.png :alt: Flatiron Center for Computational Neuroscience logo. :class: only-light :width: 20% +:target: https://www.simonsfoundation.org/flatiron/center-for-computational-neuroscience/ ``` From 01278e7c7c8439d616154363263022bfcb231289 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Sat, 16 Nov 2024 14:00:33 -0500 Subject: [PATCH 039/107] modified rtd --- .readthedocs.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 1e68ab4e..25438fee 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -17,8 +17,9 @@ build: # Check everything but the reference (because mkdocstrings do not set href=) - htmlproofer $READTHEDOCS_OUTPUT/_build/html/ --checks Links,Scripts --ignore-urls "https://fonts.gstatic.com,https://www.jneurosci.org/content/25/47/11003" --assume-extension --check-external-hash --ignore-status-codes 403 --ignore-files "/.+\/_static\/.+/","/.+\/stubs\/.+/" -mkdocs: - configuration: mkdocs.yml +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: docs/conf.py # Optionally declare the Python requirements required to build your docs python: From 06c9dede8a6345a41439558a236842f83d2de7c3 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Sat, 16 Nov 2024 14:01:07 -0500 Subject: [PATCH 040/107] removed unsesd extension --- docs/conf.py | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 824ec33c..aa6302bb 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -44,7 +44,6 @@ 'sphinx.ext.autodoc', 'sphinx.ext.napoleon', 'sphinx.ext.autosummary', - 'sphinxemoji.sphinxemoji', 'sphinx.ext.coverage', 'sphinx.ext.viewcode', # Links to source code 'sphinx.ext.doctest', From 8db2826288b3c92d558a3310458b020625925125 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Sat, 16 Nov 2024 14:11:45 -0500 Subject: [PATCH 041/107] adding lev 1 heading --- docs/quickstart.md | 2 ++ pyproject.toml | 1 + 2 files changed, 3 insertions(+) diff --git a/docs/quickstart.md b/docs/quickstart.md index 71c82331..a762466d 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -2,6 +2,8 @@ hide: - navigation --- +# Quickstart + ## **Overview** NeMoS is a neural modeling software package designed to model neural spiking activity and other time-series data diff --git a/pyproject.toml b/pyproject.toml index 3a707e31..8027549a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,6 +66,7 @@ docs = [ "sphinx-issues", "sphinxcontrib-apidoc", "sphinx-togglebutton", + "sphinx_code_tabs", "sphinxemoji", "myst-parser", "myst-nb", From 09253bb7c5c6ac2b125634d2c03bc96ef45051c6 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Sat, 16 Nov 2024 14:19:12 -0500 Subject: [PATCH 042/107] linted --- src/nemos/glm.py | 19 ++++++++++--------- src/nemos/observation_models.py | 14 ++++++++------ src/nemos/regularizer.py | 2 +- src/nemos/simulation.py | 3 ++- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/nemos/glm.py b/src/nemos/glm.py index d762a7f4..95817089 100644 --- a/src/nemos/glm.py +++ b/src/nemos/glm.py @@ -581,18 +581,19 @@ def _initialize_parameters( This method initializes the coefficients (spike basis coefficients) and intercepts (bias terms) required for the GLM. The coefficients are initialized to zeros with dimensions based on the input X. - If X is a :class:`nemos.pytrees.FeaturePytree`, the coefficients retain the pytree structure with arrays of zeros shaped - according to the features in X. If X is a simple ndarray, the coefficients are initialized as a 2D - array. The intercepts are initialized based on the log mean of the target data y across the first - axis, corresponding to the average log activity of the neuron. + If X is a :class:`nemos.pytrees.FeaturePytree`, the coefficients retain the pytree structure with + arrays of zeros shaped according to the features in X. + If X is a simple ndarray, the coefficients are initialized as a 2D array. The intercepts are initialized + based on the log mean of the target data y across the first axis, corresponding to the average log activity + of the neuron. Parameters ---------- X : - The input data which can be a :class:`nemos.pytrees.FeaturePytree` with n_features arrays of shape (n_timebins, - n_features), or a simple ndarray of shape (n_timebins, n_features). + The input data which can be a :class:`nemos.pytrees.FeaturePytree` with n_features arrays of shape + ``(n_timebins, n_features)``, or a simple ndarray of shape ``(n_timebins, n_features)``. y : - The target data array of shape (n_timebins, ), representing + The target data array of shape ``(n_timebins, )``, representing the neuron firing rates or similar metrics. Returns @@ -1535,8 +1536,8 @@ def fit( - If the mask is in array format, feature ``i`` is a predictor for neuron ``j`` if ``feature_mask[i, j] == 1``. - - If the mask is a :class:``nemos.pytrees.FeaturePytree``, then ``"feature_name"`` is a predictor of neuron ``j`` if - ``feature_mask["feature_name"][j] == 1``. + - If the mask is a :class:``nemos.pytrees.FeaturePytree``, then + ``"feature_name"`` is a predictor of neuron ``j`` if ``feature_mask["feature_name"][j] == 1``. Examples -------- diff --git a/src/nemos/observation_models.py b/src/nemos/observation_models.py index dce49032..f84dfb96 100644 --- a/src/nemos/observation_models.py +++ b/src/nemos/observation_models.py @@ -23,7 +23,8 @@ class Observations(Base, abc.ABC): This is an abstract base class used to implement observation models for neural data. Specific observation models that inherit from this class should define their versions - of the abstract methods such as :meth:`~nemos.observation_models.Observations.log_likelihood`, :meth`~nemos.observation_models.Observations.sample_generator`, and + of the abstract methods such as :meth:`~nemos.observation_models.Observations.log_likelihood`, + :meth`~nemos.observation_models.Observations.sample_generator`, and :meth:`~nemos.observation_models.Observations.deviance`. Attributes @@ -33,7 +34,7 @@ class Observations(Base, abc.ABC): See Also -------- - :class:`~nemos.observation_models.PoissonObservations` + :class:`~nemos.observation_models.PoissonObservations` A specific implementation of a observation model using the Poisson distribution. :class:`~nemos.observation_models.GammaObservations` A specific implementation of a observation model using the Gamma distribution. @@ -241,7 +242,7 @@ def estimate_scale( :math:`f(x; \theta, \phi) \propto \exp \left(a(\phi)\left( y\theta - \mathcal{k}(\theta) \right)\right)`. The relationship between variance and the scale parameter is given by: - + .. math:: \text{var}(Y) = \frac{V(\mu)}{a(\phi)}. @@ -274,8 +275,8 @@ def pseudo_r2( or by Cohen et al. [2]_. This metric evaluates the goodness-of-fit of the model relative to a null (baseline) model that assumes a - constant mean for the observations. While the pseudo-:math:`R^2` is bounded between 0 and 1 for the training set, - it can yield negative values on out-of-sample data, indicating potential over-fitting. + constant mean for the observations. While the pseudo-:math:`R^2` is bounded between 0 and 1 for the + training set, it can yield negative values on out-of-sample data, indicating potential over-fitting. Parameters ---------- @@ -302,7 +303,8 @@ def pseudo_r2( R^2_{\text{mcf}} = 1 - \frac{\log(L_{M})}{\log(L_0)}. *Equivalent to statsmodels* - `GLMResults.pseudo_rsquared(kind='mcf') `_ . + `GLMResults.pseudo_rsquared(kind='mcf') `_ . - The Cohen pseudo-:math:`R^2` is given by: diff --git a/src/nemos/regularizer.py b/src/nemos/regularizer.py index 3cc1f3eb..498eb031 100644 --- a/src/nemos/regularizer.py +++ b/src/nemos/regularizer.py @@ -101,6 +101,7 @@ class UnRegularized(Regularizer): This class equips models with the identity proximal operator (no shrinkage) and the unpenalized loss function. """ + _allowed_solvers = ( "GradientDescent", "BFGS", @@ -232,7 +233,6 @@ class Lasso(Regularizer): Lasso penalized loss function. """ - _allowed_solvers = ( "ProximalGradient", "ProxSVRG", diff --git a/src/nemos/simulation.py b/src/nemos/simulation.py index b750d454..d27bb3b3 100644 --- a/src/nemos/simulation.py +++ b/src/nemos/simulation.py @@ -63,7 +63,8 @@ def difference_of_gammas( References ---------- - .. [1] SciPy Docs - :meth:`scipy.stats.gamma ` + .. [1] SciPy Docs - + :meth:`scipy.stats.gamma ` Examples -------- From 689b6e54b22d126577e3ebb16fa15ef46983091a Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Sat, 16 Nov 2024 14:21:35 -0500 Subject: [PATCH 043/107] replaced link that was stuck --- docs/how_to_guide/plot_02_glm_demo.md | 2 +- docs/tutorials/plot_01_current_injection.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/how_to_guide/plot_02_glm_demo.md b/docs/how_to_guide/plot_02_glm_demo.md index 592bba96..f2f8a9b3 100644 --- a/docs/how_to_guide/plot_02_glm_demo.md +++ b/docs/how_to_guide/plot_02_glm_demo.md @@ -410,4 +410,4 @@ plt.legend() ``` ## References -[1] Arribas, Diego, Yuan Zhao, and Il Memming Park. "Rescuing neural spike train models from bad MLE." Advances in Neural Information Processing Systems 33 (2020): 2293-2303. +[1] Arribas, Diego, Yuan Zhao, and Il Memming Park. "Rescuing neural spike train models from bad MLE." Advances in Neural Information Processing Systems 33 (2020): 2293-2303. diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md index 9f872f74..993eaba5 100644 --- a/docs/tutorials/plot_01_current_injection.md +++ b/docs/tutorials/plot_01_current_injection.md @@ -734,6 +734,6 @@ neuron diversification. Nature, 598(7879):151-158. doi: ## References -[1] Arribas, Diego, Yuan Zhao, and Il Memming Park. "Rescuing neural spike train models from bad MLE." Advances in Neural Information Processing Systems 33 (2020): 2293-2303. +[1] Arribas, Diego, Yuan Zhao, and Il Memming Park. "Rescuing neural spike train models from bad MLE." Advances in Neural Information Processing Systems 33 (2020): 2293-2303. [2] Hocker, David, and Memming Park. "Multistep inference for generalized linear spiking models curbs runaway excitation." International IEEE/EMBS Conference on Neural Engineering, May 2017. From 23fd89bd95ff146ac599a31eb1d6a643d95b5062 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Sat, 16 Nov 2024 14:28:41 -0500 Subject: [PATCH 044/107] fixed tests --- src/nemos/basis.py | 4 ++-- tests/conftest.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nemos/basis.py b/src/nemos/basis.py index 527c6df9..ad4f0625 100644 --- a/src/nemos/basis.py +++ b/src/nemos/basis.py @@ -536,7 +536,7 @@ def __init__( # check mode if mode not in ["conv", "eval"]: raise ValueError( - f"``mode`` should be either 'conv' or 'eval'. '{mode}' provided instead!" + f"`mode` should be either 'conv' or 'eval'. '{mode}' provided instead!" ) self._mode = mode @@ -976,7 +976,7 @@ def _check_has_kernel(self) -> None: """Check that the kernel is pre-computed.""" if self.mode == "conv" and self.kernel_ is None: raise ValueError( - "You must call ``_set_kernel`` before ``_compute_features`` when mode =``conv``." + "You must call `_set_kernel` before `_compute_features` when mode =`conv`." ) def evaluate_on_grid(self, *n_samples: int) -> Tuple[Tuple[NDArray], NDArray]: diff --git a/tests/conftest.py b/tests/conftest.py index cb39ee37..77af28b5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -82,7 +82,7 @@ def initialize_params(self, *args, **kwargs): def _predict_and_compute_loss(self, params, X, y): pass - def get_optimal_solver_params_config(self): + def _get_optimal_solver_params_config(self): return None, None, None From 4dbbeec841d06ab6919c85ddc21e7f166a9d3d16 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Sat, 16 Nov 2024 14:30:20 -0500 Subject: [PATCH 045/107] fixed doctests --- src/nemos/simulation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nemos/simulation.py b/src/nemos/simulation.py index d27bb3b3..76249966 100644 --- a/src/nemos/simulation.py +++ b/src/nemos/simulation.py @@ -155,6 +155,7 @@ def regress_filter(coupling_filters: NDArray, eval_basis: NDArray) -> NDArray: >>> _, basis = RaisedCosineBasisLog(10).evaluate_on_grid(filter_duration) >>> weights = regress_filter(filter_bank, basis)[0, 0] >>> print("Weights shape:", weights.shape) + Weights shape: (10,) >>> _ = plt.plot(filter_bank[:, 0, 0], label=f"True filter") >>> _ = plt.plot(basis.dot(weights), "--", label=f"Approx. filter") >>> _ = plt.legend() From 41eba7fa25e4741507b8f2cc63e313ac5881a184 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Sat, 16 Nov 2024 14:39:18 -0500 Subject: [PATCH 046/107] removed commented conf --- docs/conf.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index aa6302bb..f73d682a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -10,21 +10,6 @@ import sys, os from pathlib import Path -# conf.py -# def strip_class_name_from_methods(app, what, name, obj, options, signature, return_annotation): -# # Check if it’s a method in a class and remove the class prefix -# if what == "method" and "." in name: -# # Only use the method part of the full name -# method_name = name.split(".")[-1] -# -# # Emit the updated signature and return annotation without class name -# return method_name + signature, return_annotation -# return signature, return_annotation -# -# def setup(app): -# app.connect("autodoc-process-signature", strip_class_name_from_methods) - - sys.path.insert(0, str(Path('..', 'src').resolve())) sys.path.insert(0, os.path.abspath('sphinxext')) From ae2b49dd772a01c1a0ed9e5e19d8fe7d334ad25e Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Sat, 16 Nov 2024 14:47:39 -0500 Subject: [PATCH 047/107] set non-interactive backend --- tox.ini | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tox.ini b/tox.ini index 7df11c35..94bd7a4f 100644 --- a/tox.ini +++ b/tox.ini @@ -8,6 +8,10 @@ envlist = py,fix # and the linters from pyproject.toml extras = dev +# Non-interactive backend for doctests +setenv = + MPLBACKEND = Agg + # Enable package caching package_cache = .tox/cache From 3323ca6401ceba932853ba96b1a1b70d171c4ed8 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Sat, 16 Nov 2024 16:17:31 -0500 Subject: [PATCH 048/107] fix rtd paths --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 25438fee..beb98fb6 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -15,7 +15,7 @@ build: - gem install html-proofer -v ">= 5.0.9" # Ensure version >= 5.0.9 post_build: # Check everything but the reference (because mkdocstrings do not set href=) - - htmlproofer $READTHEDOCS_OUTPUT/_build/html/ --checks Links,Scripts --ignore-urls "https://fonts.gstatic.com,https://www.jneurosci.org/content/25/47/11003" --assume-extension --check-external-hash --ignore-status-codes 403 --ignore-files "/.+\/_static\/.+/","/.+\/stubs\/.+/" + - htmlproofer $READTHEDOCS_OUTPUT/html --checks Links,Scripts --ignore-urls "https://fonts.gstatic.com,https://www.jneurosci.org/content/25/47/11003" --assume-extension --check-external-hash --ignore-status-codes 403 --ignore-files "/.+\/_static\/.+/","/.+\/stubs\/.+/" # Build documentation in the docs/ directory with Sphinx sphinx: From d1404e69725d1d8dea7f69a244095ccb5c9c234b Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Mon, 18 Nov 2024 10:22:56 -0500 Subject: [PATCH 049/107] smaller FI logo --- docs/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/index.md b/docs/index.md index 8ac42f9d..67f9f5a8 100644 --- a/docs/index.md +++ b/docs/index.md @@ -135,13 +135,13 @@ This package is supported by the Center for Computational Neuroscience, in the F ```{image} assets/logo_flatiron_white.svg :alt: Flatiron Center for Computational Neuroscience logo White. :class: only-dark -:width: 20% +:width: 200px :target: https://www.simonsfoundation.org/flatiron/center-for-computational-neuroscience/ ``` ```{image} assets/CCN-logo-wText.png :alt: Flatiron Center for Computational Neuroscience logo. :class: only-light -:width: 20% +:width: 200px :target: https://www.simonsfoundation.org/flatiron/center-for-computational-neuroscience/ ``` From 6fb7706ce6fe4119183770cef09d2d6bf2da5eef Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Mon, 18 Nov 2024 10:24:52 -0500 Subject: [PATCH 050/107] removed "" on admonition title --- docs/tutorials/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/README.md b/docs/tutorials/README.md index 54f9845b..5dffd196 100644 --- a/docs/tutorials/README.md +++ b/docs/tutorials/README.md @@ -2,7 +2,7 @@ A gallery of fully worked out tutorials analyzing neural recordings from different brain regions and recording modalities. -:::{dropdown} "Additional requirements" +:::{dropdown} Additional requirements :color: warning :icon: alert To run the tutorials, you may need to install some additional packages used for plotting and data fetching. From 47d3260ad2acc9b3964f794e50b31b9deb91f230 Mon Sep 17 00:00:00 2001 From: Edoardo Balzani Date: Tue, 19 Nov 2024 14:37:04 -0500 Subject: [PATCH 051/107] Update docs/tutorials/plot_02_head_direction.md Co-authored-by: William F. Broderick --- docs/tutorials/plot_02_head_direction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/plot_02_head_direction.md b/docs/tutorials/plot_02_head_direction.md index 776779e7..ce19a826 100644 --- a/docs/tutorials/plot_02_head_direction.md +++ b/docs/tutorials/plot_02_head_direction.md @@ -419,7 +419,7 @@ One way to do so is by minimizing the least-squares. lsq_coef, _, _, _ = np.linalg.lstsq(basis_kernels, np.squeeze(model.coef_), rcond=-1) # plot the basis and the approximation -doc_plots.plot_weighted_sum_basis(time, model.coef_, basis_kernels, lsq_coef) +doc_plots.plot_weighted_sum_basis(time, model.coef_, basis_kernels, lsq_coef); ``` The first plot is the response of each of the 8 basis functions to a single From 06c286e4d23ee3be4d3d569f9c584cc8265c4b65 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Tue, 19 Nov 2024 16:54:27 -0500 Subject: [PATCH 052/107] fixed "next" for dev notes --- docs/assets/stylesheets/custom.css | 7 ------- docs/developers_notes/README.md | 2 ++ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/docs/assets/stylesheets/custom.css b/docs/assets/stylesheets/custom.css index 32c2935d..3d10fd5b 100644 --- a/docs/assets/stylesheets/custom.css +++ b/docs/assets/stylesheets/custom.css @@ -128,10 +128,3 @@ aside.footnote a { aside.footnote a:hover { text-decoration: underline; /* Add underline on hover */ } - -/* Adjust spacing for the paragraph inside the footnote */ -aside.footnote p { - margin: 0.5em 0; - line-height: 1.5; /* Improve readability */ -} - diff --git a/docs/developers_notes/README.md b/docs/developers_notes/README.md index 9fd92353..6f44b3dd 100644 --- a/docs/developers_notes/README.md +++ b/docs/developers_notes/README.md @@ -1,4 +1,6 @@ +# For Developers + ## Contents ```{toctree} From 87e2a9c4c7cb552603e23c77bee929693d9493d7 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Wed, 20 Nov 2024 14:59:45 -0500 Subject: [PATCH 053/107] removed jupytext +++ --- docs/Makefile | 1 + docs/background/plot_00_conceptual_intro.md | 2 +- docs/background/plot_01_1D_basis_function.md | 2 +- docs/background/plot_02_ND_basis_function.md | 6 +++--- docs/how_to_guide/plot_02_glm_demo.md | 2 +- .../plot_05_sklearn_pipeline_cv_demo.md | 16 ++++++++-------- docs/how_to_guide/plot_06_glm_pytree.md | 2 +- docs/tutorials/plot_01_current_injection.md | 2 +- docs/tutorials/plot_02_head_direction.md | 4 ++-- docs/tutorials/plot_06_calcium_imaging.md | 6 +++--- 10 files changed, 22 insertions(+), 21 deletions(-) diff --git a/docs/Makefile b/docs/Makefile index d4bb2cbb..9d97911b 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -9,6 +9,7 @@ SOURCEDIR = . BUILDDIR = _build # Put it first so that "make" without argument is like "make help". +# Set an environ variable available during sphinx build help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/background/plot_00_conceptual_intro.md b/docs/background/plot_00_conceptual_intro.md index 57763dcc..0b5e1ed7 100644 --- a/docs/background/plot_00_conceptual_intro.md +++ b/docs/background/plot_00_conceptual_intro.md @@ -220,7 +220,7 @@ computes the rate $\lambda(t)$ using (2) and then the likelihood using ::: -+++ + ## More general GLMs So far, we have focused on the relatively simple LNP model of spike generation, which is a special case of a GLM. The LNP model has some known shortcomings[$^{[1]}$](#ref-1). For instance, LNP ignores things like refactory periods and other history-dependent features of spiking in a neuron. As we will show in other demos, such _spike history filters_ can be built into GLMs to give more accurate results. We will also show how, if you have recordings from a large _population_ of neurons simultaneously, you can build connections between the neurons into the GLM in the form of _coupling filters_. This can help answer the degree to which activity is driven primarily by the input X, or by network influences in the population. diff --git a/docs/background/plot_01_1D_basis_function.md b/docs/background/plot_01_1D_basis_function.md index b34f06e9..b1f76a6a 100644 --- a/docs/background/plot_01_1D_basis_function.md +++ b/docs/background/plot_01_1D_basis_function.md @@ -147,7 +147,7 @@ If you want to learn more about convolutions, as well as how and when to change check out the tutorial on [1D convolutions](plot_03_1D_convolution). ::: -+++ + Plotting the Basis Function Elements: -------------------------------------- diff --git a/docs/background/plot_02_ND_basis_function.md b/docs/background/plot_02_ND_basis_function.md index 017d4ce5..53d5fc63 100644 --- a/docs/background/plot_02_ND_basis_function.md +++ b/docs/background/plot_02_ND_basis_function.md @@ -86,7 +86,7 @@ In the subsequent sections, we will: Consider an instance where we want to capture a neuron's response to an animal's position within a given arena. In this scenario, the stimuli are the 2D coordinates (x, y) that represent the animal's position at each time point. -+++ + ### Additive Basis Object One way to model the response to our 2D stimuli is to hypothesize that it decomposes into two factors: @@ -277,7 +277,7 @@ A practical example would be characterizing the responses to position in a linear maze and the LFP phase angle. ::: -+++ + N-Dimensional Basis ------------------- @@ -343,7 +343,7 @@ The evaluated basis is going to be **sparse** if the basis elements support do n full domain of the basis. ::: -+++ + Here we demonstrate a shortcut syntax for multiplying bases of the same class. This is achieved using the power operator with an integer exponent. diff --git a/docs/how_to_guide/plot_02_glm_demo.md b/docs/how_to_guide/plot_02_glm_demo.md index f2f8a9b3..63469838 100644 --- a/docs/how_to_guide/plot_02_glm_demo.md +++ b/docs/how_to_guide/plot_02_glm_demo.md @@ -151,7 +151,7 @@ If the provided `solver_name` is not listed in the `allowed_solvers` this will r exception. ::: -+++ + ### Model Fit Fitting the model is as straight forward as calling the `model.fit` diff --git a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md index b37b5d8b..8563db68 100644 --- a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md +++ b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md @@ -27,7 +27,7 @@ In particular, we will learn: 4. How to select the number of bases and the basis type through cross-validation (or any other hyperparameter in the pipeline). 5. How to use a custom scoring metric to quantify the performance of each configuration. -+++ + ## What is a scikit-learn pipeline @@ -212,12 +212,12 @@ sns.despine(ax=ax) The current model captures the bimodal distribution of responses, appropriately picking out the peaks. However, it doesn't do a good job capturing the actual firing rate: the peaks are too low and the valleys are not low enough. This might be because of our choice of basis and/or regularizer strength, so let's see if tuning those parameters results in a better fit! We could do this manually, but doing this with the sklearn pipeline will make everything much easier! -+++ + ### Select the number of basis by cross-validation -+++ + :::{warning} Please keep in mind that while [`GLM.score`](nemos.glm.GLM.score) supports different ways of evaluating goodness-of-fit through the `score_type` argument, `pipeline.score(X, y, score_type="...")` does not propagate this, and uses the default value of `log-likelihood`. @@ -248,7 +248,7 @@ In order to define a parameter grid dictionary for a pipeline, you must structur The values in the dictionary are the parameters to be tested. ::: -+++ + #### Run the grid search Let's run a 5-fold cross-validation of the hyperparameters with the scikit-learn [`model_selection.GridsearchCV`](https://scikit-learn.org/1.5/modules/generated/sklearn.model_selection.GridSearchCV.html#sklearn.model_selection.GridSearchCV) class. @@ -341,7 +341,7 @@ best_n_basis = n_basis_funcs[i_best % len(n_basis_funcs)] ``` ::: -+++ + #### Visualize the scores @@ -481,7 +481,7 @@ sns.despine(ax=ax) The plot confirms that the firing rate distribution is accurately captured by our model predictions. -+++ + !!! warning Please note that because it would lead to unexpected behavior, mixing the two ways of defining values for the parameter grid is not allowed. The following would lead to an error: @@ -502,7 +502,7 @@ The plot confirms that the firing rate distribution is accurately captured by ou ``` -+++ + ## Create a custom scorer By default, the GLM score method returns the model log-likelihood. If you want to try a different metric, such as the pseudo-R2, you can create a custom scorer and pass it to the cross-validation object: @@ -534,7 +534,7 @@ gridsearch.fit(X, y) And finally, we can plot each model's score. -+++ + Plot the pseudo-R2 scores diff --git a/docs/how_to_guide/plot_06_glm_pytree.md b/docs/how_to_guide/plot_06_glm_pytree.md index 92a8a18e..a0b38b18 100644 --- a/docs/how_to_guide/plot_06_glm_pytree.md +++ b/docs/how_to_guide/plot_06_glm_pytree.md @@ -115,7 +115,7 @@ a useful function for performing computations on arbitrary pytrees, preserving their structure. -+++ + We can map lambda functions: diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md index 993eaba5..6549684f 100644 --- a/docs/tutorials/plot_01_current_injection.md +++ b/docs/tutorials/plot_01_current_injection.md @@ -391,7 +391,7 @@ rate's periodicity, and the gradual reduction in firing rate while the current remains on. -+++ + ## NeMoS diff --git a/docs/tutorials/plot_02_head_direction.md b/docs/tutorials/plot_02_head_direction.md index 776779e7..56f1126e 100644 --- a/docs/tutorials/plot_02_head_direction.md +++ b/docs/tutorials/plot_02_head_direction.md @@ -263,7 +263,7 @@ instead the feature dimension is 80, because our bin size was 0.01 sec and the w We can learn these weights by maximum likelihood by fitting a GLM. -+++ + #### Fitting the Model @@ -462,7 +462,7 @@ doc_plots.plot_convolved_counts(neuron_count, conv_spk, epoch_one_spk, epoch_mul Now that we have our "compressed" history feature matrix, we can fit the ML parameters for a GLM. -+++ + #### Fit and compare the models diff --git a/docs/tutorials/plot_06_calcium_imaging.md b/docs/tutorials/plot_06_calcium_imaging.md index fb896c5a..151c6d74 100644 --- a/docs/tutorials/plot_06_calcium_imaging.md +++ b/docs/tutorials/plot_06_calcium_imaging.md @@ -97,7 +97,7 @@ plt.tight_layout() You can see that the calcium signals are both nonnegative, and noisy. One (neuron 4) has much higher SNR than the other. We cannot typically resolve individual action potentials, but instead see slow calcium fluctuations that result from an unknown underlying electrical signal (estimating the spikes from calcium traces is known as _deconvolution_ and is beyond the scope of this demo). -+++ + We can also plot tuning curves, plotting mean calcium activity as a function of head direction, using the function [`compute_1d_tuning_curves_continuous`](https://pynapple.org/generated/pynapple.process.tuning_curves.html#pynapple.process.tuning_curves.compute_1d_tuning_curves_continuous). Here `data['ry']` is a [`Tsd`](https://pynapple.org/generated/pynapple.core.time_series.Tsd.html) that contains the angular head-direction of the animal between 0 and 2$\pi$. @@ -145,7 +145,7 @@ plt.show() The downsampling did not destroy the fast transient dynamics, so seems fine to use. We can now move on to using NeMoS to fit a model. -+++ + ## Basis instantiation @@ -261,7 +261,7 @@ model.fit(Xtrain, Ytrain[:, neu]) ## Model comparison -+++ + We can compare this to scikit-learn [linear regression](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html). From 3316abbb876812d6993418de5f179e7114013195 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Wed, 20 Nov 2024 15:52:02 -0500 Subject: [PATCH 054/107] added image checks --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index beb98fb6..6597da0a 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -15,7 +15,7 @@ build: - gem install html-proofer -v ">= 5.0.9" # Ensure version >= 5.0.9 post_build: # Check everything but the reference (because mkdocstrings do not set href=) - - htmlproofer $READTHEDOCS_OUTPUT/html --checks Links,Scripts --ignore-urls "https://fonts.gstatic.com,https://www.jneurosci.org/content/25/47/11003" --assume-extension --check-external-hash --ignore-status-codes 403 --ignore-files "/.+\/_static\/.+/","/.+\/stubs\/.+/" + - htmlproofer $READTHEDOCS_OUTPUT/html --checks Links,Scripts,Images --ignore-urls "https://fonts.gstatic.com,https://www.jneurosci.org/content/25/47/11003" --assume-extension --check-external-hash --ignore-status-codes 403 --ignore-files "/.+\/_static\/.+/","/.+\/stubs\/.+/" # Build documentation in the docs/ directory with Sphinx sphinx: From 6f01d9e97d24765917f34d188b9ae6e188ef47bc Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Wed, 20 Nov 2024 15:52:29 -0500 Subject: [PATCH 055/107] try fixing item lists in rst in docstrings --- src/nemos/basis.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/nemos/basis.py b/src/nemos/basis.py index ad4f0625..d572c502 100644 --- a/src/nemos/basis.py +++ b/src/nemos/basis.py @@ -1328,6 +1328,7 @@ def split_by_feature( - If the basis expects an input shape ``(n_samples, n_inputs)``, then the feature axis length will be ``total_n_features = n_inputs * n_basis_funcs``. This axis is reshaped into dimensions ``(n_inputs, n_basis_funcs)``. + - If the basis expects an input of shape ``(n_samples,)``, then the feature axis length will be ``total_n_features = n_basis_funcs``. This axis is reshaped into ``(1, n_basis_funcs)``. @@ -1345,7 +1346,9 @@ def split_by_feature( number of features generated by the basis, i.e., ``self.n_output_features``. **Examples:** + - For a design matrix: ``(n_samples, total_n_features)`` + - For model coefficients: ``(total_n_features,)`` or ``(total_n_features, n_neurons)``. axis : int, optional From 3cb19470f483f997a2f2a8ad210979b14e0e0f0f Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Wed, 20 Nov 2024 15:52:50 -0500 Subject: [PATCH 056/107] remove footnotes css --- docs/assets/stylesheets/custom.css | 48 +++++++++--------------------- 1 file changed, 14 insertions(+), 34 deletions(-) diff --git a/docs/assets/stylesheets/custom.css b/docs/assets/stylesheets/custom.css index 3d10fd5b..f7dc7a81 100644 --- a/docs/assets/stylesheets/custom.css +++ b/docs/assets/stylesheets/custom.css @@ -94,37 +94,17 @@ html[data-theme=light]{ font-weight: normal; } -/* Add a line separator above the entire footnote list */ -aside.footnote-list { - border-top: 1px solid #ccc; /* Add a horizontal line */ - margin-top: 2em; /* Space above the separator */ - padding-top: 1em; /* Space below the separator */ -} - -/* Style each individual footnote */ -aside.footnote { - margin-bottom: 1em; /* Add space between footnotes */ - font-size: 0.9em; /* Adjust font size */ - color: #333; /* Text color */ -} - -/* Style the label (the bracketed number) */ -aside.footnote .label { - font-weight: bold; /* Make it stand out */ - margin-right: 0.5em; /* Add space after the label */ -} - -/* Style the brackets */ -span.fn-bracket { - color: #666; /* Dim the brackets */ -} - -/* Style the links within the footnotes */ -aside.footnote a { - color: #007BFF; /* Blue link color */ - text-decoration: none; /* Remove underline */ -} - -aside.footnote a:hover { - text-decoration: underline; /* Add underline on hover */ -} +/*!* Style the brackets *!*/ +/*span.fn-bracket {*/ +/* color: #666; !* Dim the brackets *!*/ +/*}*/ + +/*!* Style the links within the footnotes *!*/ +/*aside.footnote a {*/ +/* color: #007BFF; !* Blue link color *!*/ +/* text-decoration: none; !* Remove underline *!*/ +/*}*/ + +/*aside.footnote a:hover {*/ +/* text-decoration: underline; !* Add underline on hover *!*/ +/*}*/ From e21f185642cb1795a977f7229f00242f7f0aa798 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Wed, 20 Nov 2024 15:53:08 -0500 Subject: [PATCH 057/107] potentially fix progress bar --- src/nemos/fetch/fetch_data.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/nemos/fetch/fetch_data.py b/src/nemos/fetch/fetch_data.py index 1246c993..aadb44b7 100644 --- a/src/nemos/fetch/fetch_data.py +++ b/src/nemos/fetch/fetch_data.py @@ -14,6 +14,7 @@ try: import pooch from pooch import Pooch + from tqdm.auto import tqdm except ImportError: pooch = None Pooch = None @@ -124,7 +125,7 @@ def fetch_data( ) retriever = _create_retriever(path) # Fetch the dataset using pooch. - return retriever.fetch(dataset_name, progressbar=True) + return retriever.fetch(dataset_name, progressbar=tqdm) def download_dandi_data(dandiset_id: str, filepath: str) -> NWBHDF5IO: From bad2adb7b35566b86948c34501d5164743f9cc9f Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Wed, 20 Nov 2024 15:53:20 -0500 Subject: [PATCH 058/107] priority to getting help --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 67f9f5a8..4da5ef06 100644 --- a/docs/index.md +++ b/docs/index.md @@ -14,8 +14,8 @@ Quickstart Background How-To Guide Tutorials -API Reference Getting Help +API Reference For Developers ``` From f70a42b8c417e08c8ac01909c54070a4cb6d922d Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Wed, 20 Nov 2024 15:53:35 -0500 Subject: [PATCH 059/107] leftover admonition fix --- docs/installation.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index b8cfd47e..0c2572d7 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -57,8 +57,11 @@ To install NeMoS on a system without a GPU, run this command from within your ac ### GPU Installation -!!! warning - JAX does not guarantee GPU support for Windows, see [here](https://jax.readthedocs.io/en/latest/installation.html#supported-platforms) for updates. +:::{warning} + +JAX does not guarantee GPU support for Windows, see [here](https://jax.readthedocs.io/en/latest/installation.html#supported-platforms) for updates. + +::: For systems equipped with a GPU, you need to specifically install the GPU-enabled versions of `jax` and `jaxlib` before installing NeMoS. From 17082418867bce6b7e70db2294d6f69188e2d046 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Wed, 20 Nov 2024 15:55:52 -0500 Subject: [PATCH 060/107] remove logging --- src/nemos/_documentation_utils/plotting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nemos/_documentation_utils/plotting.py b/src/nemos/_documentation_utils/plotting.py index 5514787f..6072e277 100644 --- a/src/nemos/_documentation_utils/plotting.py +++ b/src/nemos/_documentation_utils/plotting.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 +import os from typing import Optional, Union import jax @@ -40,7 +41,6 @@ "Feel free to use them, but they will probably not work as intended with other datasets / in other contexts." ) - def lnp_schematic( input_feature: nap.Tsd, weights: np.ndarray, From bbb4dc33713a98853d58300a26f2eb6fa18334c5 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Wed, 20 Nov 2024 15:56:20 -0500 Subject: [PATCH 061/107] added ipythonwidgets --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 8027549a..6cc3681f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,6 +78,7 @@ docs = [ "matplotlib>=3.7", "seaborn", "pooch", + "ipywidgets", ] examples = [ "scikit-learn", From 11cf0ae37b63c04cb610183044dae21648efa195 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Wed, 20 Nov 2024 16:37:51 -0500 Subject: [PATCH 062/107] fixed links --- .readthedocs.yaml | 8 +++++--- docs/conf.py | 5 ----- docs/developers_notes/03-glm.md | 2 +- docs/quickstart.md | 2 +- docs/tutorials/plot_01_current_injection.md | 4 ++-- 5 files changed, 9 insertions(+), 12 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 6597da0a..9487785e 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -14,9 +14,11 @@ build: pre_build: - gem install html-proofer -v ">= 5.0.9" # Ensure version >= 5.0.9 post_build: - # Check everything but the reference (because mkdocstrings do not set href=) - - htmlproofer $READTHEDOCS_OUTPUT/html --checks Links,Scripts,Images --ignore-urls "https://fonts.gstatic.com,https://www.jneurosci.org/content/25/47/11003" --assume-extension --check-external-hash --ignore-status-codes 403 --ignore-files "/.+\/_static\/.+/","/.+\/stubs\/.+/" - + # Check everything except 403s and a jneurosci, which returns 404 but the link works when clicking. + - htmlproofer $READTHEDOCS_OUTPUT/html --checks Links,Scripts,Images --ignore-urls "https://fonts.gstatic.com,https://www.jneurosci.org/content/25/47/11003" --assume-extension --check-external-hash --ignore-status-codes 403 --ignore-files "/.+\/_static\/.+/","/.+\/stubs\/.+/","/.+\/tutorials/plot_02_head_direction.+/" + # The auto-generated animation doesn't have a alt or src/srcset; I am able to ignore missing alt, but I cannot work around a missing src/srcset + # therefore for this file I am not checking the figures. + - htmlproofer $READTHEDOCS_OUTPUT/html/tutorials/plot_02_head_direction.html --checks Links,Scripts --ignore-urls "https://www.jneurosci.org/content/25/47/11003" # Build documentation in the docs/ directory with Sphinx sphinx: configuration: docs/conf.py diff --git a/docs/conf.py b/docs/conf.py index f73d682a..94a3948d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -122,11 +122,6 @@ } } -html_context = { - "default_mode": "light", -} - - html_sidebars = { "index": [], "installation":[], diff --git a/docs/developers_notes/03-glm.md b/docs/developers_notes/03-glm.md index 366c08ce..2ab98f10 100644 --- a/docs/developers_notes/03-glm.md +++ b/docs/developers_notes/03-glm.md @@ -19,7 +19,7 @@ Instantiating a specific GLM simply requires providing an observation model (Gam
- + NeMoS classes.
Schematic of the module interactions.
diff --git a/docs/quickstart.md b/docs/quickstart.md index a762466d..72b69536 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -153,7 +153,7 @@ The `basis` module includes objects that perform two types of transformations on ### **Non-linear Mapping**
- + GLM Feature Scheme
Figure 1: Basis as non-linear mappings. The figure demonstrate the use of basis functions to create complex non-linear features for a GLM.
diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md index 6549684f..f06109aa 100644 --- a/docs/tutorials/plot_01_current_injection.md +++ b/docs/tutorials/plot_01_current_injection.md @@ -31,7 +31,7 @@ the experimentalists injected three pulses of current. The current is a square pulse multiplied by a sinusoid of a fixed frequency, with some random noise riding on top. -![Allen Brain Atlas view of the data we will analyze.](../../assets/allen_data.png) +![Allen Brain Atlas view of the data we will analyze.](../assets/allen_data.png) In the figure above (from the Allen Brain Atlas website), we see the approximately 22 second sweep, with the input current plotted in the first row, @@ -121,7 +121,7 @@ The dataset contains several different pynapple objects, which we will explore throughout this demo. The following illustrates how these fields relate to the data we visualized above: -![Annotated view of the data we will analyze.](../../assets/allen_data_annotated.gif) +![Annotated view of the data we will analyze.](../assets/allen_data_annotated.gif) - `units`: dictionary of neurons, holding each neuron's spike timestamps. From 287b90301e2043677695b89538809a8cecc499e5 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 16:23:01 -0500 Subject: [PATCH 063/107] added thumbnail for background --- .../background/convolutions_valid_mode.svg | 2840 ++++++ .../background/multiplicative_basis.svg | 8618 +++++++++++++++++ .../background/one_dim_bspline_basis.svg | 1294 +++ docs/background/README.md | 22 + docs/background/plot_00_conceptual_intro.md | 2 + docs/background/plot_01_1D_basis_function.md | 16 +- docs/background/plot_02_ND_basis_function.md | 13 +- docs/background/plot_03_1D_convolution.md | 16 +- 8 files changed, 12816 insertions(+), 5 deletions(-) create mode 100644 docs/assets/thumbnails/background/convolutions_valid_mode.svg create mode 100644 docs/assets/thumbnails/background/multiplicative_basis.svg create mode 100644 docs/assets/thumbnails/background/one_dim_bspline_basis.svg diff --git a/docs/assets/thumbnails/background/convolutions_valid_mode.svg b/docs/assets/thumbnails/background/convolutions_valid_mode.svg new file mode 100644 index 00000000..77528e4b --- /dev/null +++ b/docs/assets/thumbnails/background/convolutions_valid_mode.svg @@ -0,0 +1,2840 @@ + + + + + + + + 2024-11-21T16:19:56.419950 + image/svg+xml + + + Matplotlib v3.9.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/thumbnails/background/multiplicative_basis.svg b/docs/assets/thumbnails/background/multiplicative_basis.svg new file mode 100644 index 00000000..0309ad44 --- /dev/null +++ b/docs/assets/thumbnails/background/multiplicative_basis.svg @@ -0,0 +1,8618 @@ + + + + + + + + 2024-11-21T16:22:58.262336 + image/svg+xml + + + Matplotlib v3.9.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/thumbnails/background/one_dim_bspline_basis.svg b/docs/assets/thumbnails/background/one_dim_bspline_basis.svg new file mode 100644 index 00000000..434ecd38 --- /dev/null +++ b/docs/assets/thumbnails/background/one_dim_bspline_basis.svg @@ -0,0 +1,1294 @@ + + + + + + + + 2024-11-21T16:22:50.988028 + image/svg+xml + + + Matplotlib v3.9.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/background/README.md b/docs/background/README.md index c4fa1093..a4ae96a9 100644 --- a/docs/background/README.md +++ b/docs/background/README.md @@ -14,9 +14,16 @@ pip install nemos[examples] ::: + ::::{grid} 1 2 3 3 :::{grid-item-card} + +
+Linear-Non Linear-Poisson illustration. +
+ + ```{toctree} :maxdepth: 2 @@ -25,6 +32,11 @@ plot_00_conceptual_intro.md ::: :::{grid-item-card} + +
+Linear-Non Linear-Poisson illustration. +
+ ```{toctree} :maxdepth: 2 @@ -33,6 +45,11 @@ plot_01_1D_basis_function.md ::: :::{grid-item-card} + +
+Linear-Non Linear-Poisson illustration. +
+ ```{toctree} :maxdepth: 2 @@ -41,6 +58,11 @@ plot_02_ND_basis_function.md ::: :::{grid-item-card} + +
+Linear-Non Linear-Poisson illustration. +
+ ```{toctree} :maxdepth: 2 diff --git a/docs/background/plot_00_conceptual_intro.md b/docs/background/plot_00_conceptual_intro.md index 0b5e1ed7..193a5a4c 100644 --- a/docs/background/plot_00_conceptual_intro.md +++ b/docs/background/plot_00_conceptual_intro.md @@ -12,6 +12,8 @@ kernelspec: --- ```{code-cell} ipython3 +:tags: [hide-input] + %matplotlib inline ``` (glm_intro_background)= diff --git a/docs/background/plot_01_1D_basis_function.md b/docs/background/plot_01_1D_basis_function.md index b1f76a6a..c092ebcb 100644 --- a/docs/background/plot_01_1D_basis_function.md +++ b/docs/background/plot_01_1D_basis_function.md @@ -48,6 +48,7 @@ is defined by the samples that we input to the [`__call__`](nemos.basis.Basis.__ ```{code-cell} ipython3 + # Generate a time series of sample points samples = nap.Tsd(t=np.arange(1001), d=np.linspace(0, 1,1001)) @@ -58,9 +59,20 @@ eval_basis = bspline(samples) print(f"Evaluated B-spline of order {order} with {eval_basis.shape[1]} " f"basis element and {eval_basis.shape[0]} samples.") -plt.figure() +fig = plt.figure() plt.title("B-spline basis") -plt.plot(eval_basis) +_ = plt.plot(eval_basis) +``` + +```{code-cell} ipython3 +:tags: [hide-input] + +# save image for thumbnail +from pathlib import Path + +path = Path("../assets/thumbnails/background") +if path.exists(): + fig.savefig(path / "one_dim_bspline_basis.svg") ``` ## Setting the basis support diff --git a/docs/background/plot_02_ND_basis_function.md b/docs/background/plot_02_ND_basis_function.md index 53d5fc63..1d43ab00 100644 --- a/docs/background/plot_02_ND_basis_function.md +++ b/docs/background/plot_02_ND_basis_function.md @@ -233,8 +233,6 @@ and we visualize the corresponding product. ```{code-cell} ipython3 -# Set this figure as the thumbnail -# mkdocs_gallery_thumbnail_number = 3 X, Y, Z = prod_basis.evaluate_on_grid(200, 200) @@ -270,6 +268,17 @@ axs[2, 1].set_xlabel('y-coord') plt.tight_layout() ``` +```{code-cell} ipython3 +:tags: [hide-input] + +# save image for thumbnail +from pathlib import Path + +path = Path("../assets/thumbnails/background") +if path.exists(): + fig.savefig(path / "multiplicative_basis.svg") +``` + :::{info} Basis objects of different types can be combined through multiplication or addition. This feature is particularly useful when one of the axes represents a periodic variable and another is non-periodic. diff --git a/docs/background/plot_03_1D_convolution.md b/docs/background/plot_03_1D_convolution.md index fe25a6d6..012b07ae 100644 --- a/docs/background/plot_03_1D_convolution.md +++ b/docs/background/plot_03_1D_convolution.md @@ -12,6 +12,8 @@ kernelspec: --- ```{code-cell} ipython3 +:tags: [hide-input] + %matplotlib inline ``` @@ -112,7 +114,7 @@ rect_acausal_right = patches.Rectangle((len(spk) - (ws-1)//2, -2.5), (ws-1)//2, # Set this figure as the thumbnail # mkdocs_gallery_thumbnail_number = 2 -plt.figure(figsize=(6, 4)) +fig = plt.figure(figsize=(6, 4)) shift_spk = - spk - 0.1 ax = plt.subplot(311) @@ -136,6 +138,18 @@ plt.vlines(np.arange(spk.shape[0]), 0, shift_spk, color='k') plt.plot(np.arange(spk.shape[0]), spk_acausal_conv) plt.ylabel('acausal') plt.tight_layout() + +``` + +```{code-cell} ipython3 +:tags: [hide-input] + +# save image for thumbnail +from pathlib import Path + +path = Path("../assets/thumbnails/background") +if path.exists(): + fig.savefig(path / "convolutions_valid_mode.svg") ``` ## Convolve using [`Basis.compute_features`](nemos.basis.Basis.compute_features) From 904c7d0a5d6b981253e2b443534aa3c60fa7e31d Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 16:29:05 -0500 Subject: [PATCH 064/107] add images tutorials --- .../background/convolutions_valid_mode.svg | 692 +++++++++--------- .../tutorials/current_injection.svg | 32 + .../tutorials/rates_and_smoothed_counts.svg | 32 + docs/tutorials/plot_01_current_injection.md | 11 + docs/tutorials/plot_02_head_direction.md | 11 + 5 files changed, 432 insertions(+), 346 deletions(-) create mode 100644 docs/assets/thumbnails/tutorials/current_injection.svg create mode 100644 docs/assets/thumbnails/tutorials/rates_and_smoothed_counts.svg diff --git a/docs/assets/thumbnails/background/convolutions_valid_mode.svg b/docs/assets/thumbnails/background/convolutions_valid_mode.svg index 77528e4b..3de128d6 100644 --- a/docs/assets/thumbnails/background/convolutions_valid_mode.svg +++ b/docs/assets/thumbnails/background/convolutions_valid_mode.svg @@ -6,7 +6,7 @@ - 2024-11-21T16:19:56.419950 + 2024-11-21T16:23:04.671790 image/svg+xml @@ -43,18 +43,18 @@ L 97.982668 83.350909 L 97.982668 29.569091 L 63.579545 29.569091 z -" clip-path="url(#p9bd67c3bc7)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> +" clip-path="url(#p8b105a05eb)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> - - + @@ -90,7 +90,7 @@ z - + @@ -130,7 +130,7 @@ z - + @@ -165,7 +165,7 @@ z - + @@ -211,7 +211,7 @@ z - + @@ -266,7 +266,7 @@ z - + @@ -299,12 +299,12 @@ z - - + @@ -361,7 +361,7 @@ z - + @@ -376,7 +376,7 @@ z - + @@ -519,304 +519,304 @@ z +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8b105a05eb)" style="fill: none; stroke: #2ca02c; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> - + @@ -1291,7 +1291,7 @@ z - + @@ -1305,7 +1305,7 @@ z - + @@ -1319,7 +1319,7 @@ z - + @@ -1333,7 +1333,7 @@ z - + @@ -1347,7 +1347,7 @@ z - + @@ -1364,7 +1364,7 @@ z - + @@ -1380,7 +1380,7 @@ z - + @@ -1395,7 +1395,7 @@ z - + @@ -1450,304 +1450,304 @@ z +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4e2d35e9d2)" style="fill: none; stroke: #2ca02c; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p241c04fa23)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> +" clip-path="url(#p241c04fa23)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> - + @@ -2091,7 +2091,7 @@ z - + @@ -2105,7 +2105,7 @@ z - + @@ -2119,7 +2119,7 @@ z - + @@ -2133,7 +2133,7 @@ z - + @@ -2147,7 +2147,7 @@ z - + @@ -2164,7 +2164,7 @@ z - + @@ -2180,7 +2180,7 @@ z - + @@ -2195,7 +2195,7 @@ z - + @@ -2223,304 +2223,304 @@ z +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p241c04fa23)" style="fill: none; stroke: #2ca02c; stroke-width: 1.5; stroke-linecap: square"/> + - + - + diff --git a/docs/assets/thumbnails/tutorials/current_injection.svg b/docs/assets/thumbnails/tutorials/current_injection.svg new file mode 100644 index 00000000..e9a31790 --- /dev/null +++ b/docs/assets/thumbnails/tutorials/current_injection.svg @@ -0,0 +1,32 @@ + + + + + + + + 2024-11-21T16:27:24.957210 + image/svg+xml + + + Matplotlib v3.9.2, https://matplotlib.org/ + + + + + + + + + + + + + + diff --git a/docs/assets/thumbnails/tutorials/rates_and_smoothed_counts.svg b/docs/assets/thumbnails/tutorials/rates_and_smoothed_counts.svg new file mode 100644 index 00000000..53a33b72 --- /dev/null +++ b/docs/assets/thumbnails/tutorials/rates_and_smoothed_counts.svg @@ -0,0 +1,32 @@ + + + + + + + + 2024-11-21T16:28:25.594705 + image/svg+xml + + + Matplotlib v3.9.2, https://matplotlib.org/ + + + + + + + + + + + + + + diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md index f06109aa..524b1268 100644 --- a/docs/tutorials/plot_01_current_injection.md +++ b/docs/tutorials/plot_01_current_injection.md @@ -594,6 +594,17 @@ doc_plots.current_injection_plot(current, spikes, firing_rate, predicted_firing_rate=smooth_predicted_fr) ``` +```{code-cell} ipython3 +:tags: [hide-input] + +# save image for thumbnail +from pathlib import Path + +path = Path("../assets/thumbnails/tutorials") +if path.exists(): + plt.savefig(path / "current_injection.svg") +``` + What do we see above? Note that the y-axes in the final row are different for each subplot! diff --git a/docs/tutorials/plot_02_head_direction.md b/docs/tutorials/plot_02_head_direction.md index 98b24b3c..e29b7e39 100644 --- a/docs/tutorials/plot_02_head_direction.md +++ b/docs/tutorials/plot_02_head_direction.md @@ -640,6 +640,17 @@ doc_plots.plot_rates_and_smoothed_counts( ); ``` +```{code-cell} ipython3 +:tags: [hide-input] + +# save image for thumbnail +from pathlib import Path + +path = Path("../assets/thumbnails/tutorials") +if path.exists(): + plt.savefig(path / "rates_and_smoothed_counts.svg") +``` + #### Visualizing the connectivity Compute the tuning curve form the predicted rates. From c67be3d64145d81e49ba97170e85e90160d2ac70 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 16:41:06 -0500 Subject: [PATCH 065/107] add thumbnails tutorials --- .../background/plot_00_conceptual_intro.svg | 415 ++++++++++++++++++ ...asis.svg => plot_01_1D_basis_function.svg} | 0 ...asis.svg => plot_02_ND_basis_function.svg} | 0 ...id_mode.svg => plot_03_1D_convolution.svg} | 0 ...tion.svg => plot_01_current_injection.svg} | 2 +- ..._counts.svg => plot_02_head_direction.svg} | 2 +- .../tutorials/plot_03_grid_cells.svg | 32 ++ .../thumbnails/tutorials/plot_04_v1_cells.svg | 32 ++ .../tutorials/plot_05_place_cells.svg | 32 ++ .../tutorials/plot_06_calcium_imaging.svg | 32 ++ docs/background/README.md | 8 +- docs/tutorials/plot_01_current_injection.md | 2 +- docs/tutorials/plot_02_head_direction.md | 2 +- docs/tutorials/plot_03_grid_cells.md | 11 + docs/tutorials/plot_04_v1_cells.md | 11 + docs/tutorials/plot_05_place_cells.md | 11 + docs/tutorials/plot_06_calcium_imaging.md | 12 + 17 files changed, 596 insertions(+), 8 deletions(-) create mode 100644 docs/assets/thumbnails/background/plot_00_conceptual_intro.svg rename docs/assets/thumbnails/background/{one_dim_bspline_basis.svg => plot_01_1D_basis_function.svg} (100%) rename docs/assets/thumbnails/background/{multiplicative_basis.svg => plot_02_ND_basis_function.svg} (100%) rename docs/assets/thumbnails/background/{convolutions_valid_mode.svg => plot_03_1D_convolution.svg} (100%) rename docs/assets/thumbnails/tutorials/{current_injection.svg => plot_01_current_injection.svg} (95%) rename docs/assets/thumbnails/tutorials/{rates_and_smoothed_counts.svg => plot_02_head_direction.svg} (95%) create mode 100644 docs/assets/thumbnails/tutorials/plot_03_grid_cells.svg create mode 100644 docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg create mode 100644 docs/assets/thumbnails/tutorials/plot_05_place_cells.svg create mode 100644 docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg diff --git a/docs/assets/thumbnails/background/plot_00_conceptual_intro.svg b/docs/assets/thumbnails/background/plot_00_conceptual_intro.svg new file mode 100644 index 00000000..6757f795 --- /dev/null +++ b/docs/assets/thumbnails/background/plot_00_conceptual_intro.svg @@ -0,0 +1,415 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e + x + + Nonlinearity + Linear filter + + + + + + + Poisson + Spikes + Input + GLM model + + diff --git a/docs/assets/thumbnails/background/one_dim_bspline_basis.svg b/docs/assets/thumbnails/background/plot_01_1D_basis_function.svg similarity index 100% rename from docs/assets/thumbnails/background/one_dim_bspline_basis.svg rename to docs/assets/thumbnails/background/plot_01_1D_basis_function.svg diff --git a/docs/assets/thumbnails/background/multiplicative_basis.svg b/docs/assets/thumbnails/background/plot_02_ND_basis_function.svg similarity index 100% rename from docs/assets/thumbnails/background/multiplicative_basis.svg rename to docs/assets/thumbnails/background/plot_02_ND_basis_function.svg diff --git a/docs/assets/thumbnails/background/convolutions_valid_mode.svg b/docs/assets/thumbnails/background/plot_03_1D_convolution.svg similarity index 100% rename from docs/assets/thumbnails/background/convolutions_valid_mode.svg rename to docs/assets/thumbnails/background/plot_03_1D_convolution.svg diff --git a/docs/assets/thumbnails/tutorials/current_injection.svg b/docs/assets/thumbnails/tutorials/plot_01_current_injection.svg similarity index 95% rename from docs/assets/thumbnails/tutorials/current_injection.svg rename to docs/assets/thumbnails/tutorials/plot_01_current_injection.svg index e9a31790..f106703f 100644 --- a/docs/assets/thumbnails/tutorials/current_injection.svg +++ b/docs/assets/thumbnails/tutorials/plot_01_current_injection.svg @@ -6,7 +6,7 @@ - 2024-11-21T16:27:24.957210 + 2024-11-21T16:39:51.482044 image/svg+xml diff --git a/docs/assets/thumbnails/tutorials/rates_and_smoothed_counts.svg b/docs/assets/thumbnails/tutorials/plot_02_head_direction.svg similarity index 95% rename from docs/assets/thumbnails/tutorials/rates_and_smoothed_counts.svg rename to docs/assets/thumbnails/tutorials/plot_02_head_direction.svg index 53a33b72..b0fdfa87 100644 --- a/docs/assets/thumbnails/tutorials/rates_and_smoothed_counts.svg +++ b/docs/assets/thumbnails/tutorials/plot_02_head_direction.svg @@ -6,7 +6,7 @@ - 2024-11-21T16:28:25.594705 + 2024-11-21T16:40:15.985300 image/svg+xml diff --git a/docs/assets/thumbnails/tutorials/plot_03_grid_cells.svg b/docs/assets/thumbnails/tutorials/plot_03_grid_cells.svg new file mode 100644 index 00000000..43758eef --- /dev/null +++ b/docs/assets/thumbnails/tutorials/plot_03_grid_cells.svg @@ -0,0 +1,32 @@ + + + + + + + + 2024-11-21T16:39:35.168729 + image/svg+xml + + + Matplotlib v3.9.2, https://matplotlib.org/ + + + + + + + + + + + + + + diff --git a/docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg b/docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg new file mode 100644 index 00000000..3953ccb7 --- /dev/null +++ b/docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg @@ -0,0 +1,32 @@ + + + + + + + + 2024-11-21T16:39:08.264295 + image/svg+xml + + + Matplotlib v3.9.2, https://matplotlib.org/ + + + + + + + + + + + + + + diff --git a/docs/assets/thumbnails/tutorials/plot_05_place_cells.svg b/docs/assets/thumbnails/tutorials/plot_05_place_cells.svg new file mode 100644 index 00000000..684518bf --- /dev/null +++ b/docs/assets/thumbnails/tutorials/plot_05_place_cells.svg @@ -0,0 +1,32 @@ + + + + + + + + 2024-11-21T16:38:04.234838 + image/svg+xml + + + Matplotlib v3.9.2, https://matplotlib.org/ + + + + + + + + + + + + + + diff --git a/docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg b/docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg new file mode 100644 index 00000000..d48562d5 --- /dev/null +++ b/docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg @@ -0,0 +1,32 @@ + + + + + + + + 2024-11-21T16:38:30.602908 + image/svg+xml + + + Matplotlib v3.9.2, https://matplotlib.org/ + + + + + + + + + + + + + + diff --git a/docs/background/README.md b/docs/background/README.md index a4ae96a9..10658243 100644 --- a/docs/background/README.md +++ b/docs/background/README.md @@ -20,7 +20,7 @@ pip install nemos[examples] :::{grid-item-card}
-Linear-Non Linear-Poisson illustration. +Linear-Non Linear-Poisson illustration.
@@ -34,7 +34,7 @@ plot_00_conceptual_intro.md :::{grid-item-card}
-Linear-Non Linear-Poisson illustration. +Linear-Non Linear-Poisson illustration.
```{toctree} @@ -47,7 +47,7 @@ plot_01_1D_basis_function.md :::{grid-item-card}
-Linear-Non Linear-Poisson illustration. +Linear-Non Linear-Poisson illustration.
```{toctree} @@ -60,7 +60,7 @@ plot_02_ND_basis_function.md :::{grid-item-card}
-Linear-Non Linear-Poisson illustration. +Linear-Non Linear-Poisson illustration.
```{toctree} diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md index 524b1268..74e58589 100644 --- a/docs/tutorials/plot_01_current_injection.md +++ b/docs/tutorials/plot_01_current_injection.md @@ -602,7 +602,7 @@ from pathlib import Path path = Path("../assets/thumbnails/tutorials") if path.exists(): - plt.savefig(path / "current_injection.svg") + plt.savefig(path / "plot_01_current_injection.svg") ``` What do we see above? Note that the y-axes in the final row are different for diff --git a/docs/tutorials/plot_02_head_direction.md b/docs/tutorials/plot_02_head_direction.md index e29b7e39..64114d90 100644 --- a/docs/tutorials/plot_02_head_direction.md +++ b/docs/tutorials/plot_02_head_direction.md @@ -648,7 +648,7 @@ from pathlib import Path path = Path("../assets/thumbnails/tutorials") if path.exists(): - plt.savefig(path / "rates_and_smoothed_counts.svg") + plt.savefig(path / "plot_02_head_direction.svg") ``` #### Visualizing the connectivity diff --git a/docs/tutorials/plot_03_grid_cells.md b/docs/tutorials/plot_03_grid_cells.md index c46ecd6a..45f42e46 100644 --- a/docs/tutorials/plot_03_grid_cells.md +++ b/docs/tutorials/plot_03_grid_cells.md @@ -303,3 +303,14 @@ axs[2].set_title(f"Ridge - strength: {best_model.regularizer_strength}") axs[2].imshow(smooth_best_model, vmin=vmin, vmax=vmax) plt.tight_layout() ``` + +```{code-cell} ipython3 +:tags: [hide-input] + +# save image for thumbnail +from pathlib import Path + +path = Path("../assets/thumbnails/tutorials") +if path.exists(): + plt.savefig(path / "plot_03_grid_cells.svg") +``` \ No newline at end of file diff --git a/docs/tutorials/plot_04_v1_cells.md b/docs/tutorials/plot_04_v1_cells.md index cfe594b9..5505dc3e 100644 --- a/docs/tutorials/plot_04_v1_cells.md +++ b/docs/tutorials/plot_04_v1_cells.md @@ -207,6 +207,17 @@ fig, ax = plt.subplots(1, 1, figsize=(4,4)) ax.imshow(receptive_field, cmap='Greys_r') ``` +```{code-cell} ipython3 +:tags: [hide-input] + +# save image for thumbnail +from pathlib import Path + +path = Path("../assets/thumbnails/tutorials") +if path.exists(): + plt.savefig(path / "plot_04_v1_cells.svg") +``` + This receptive field gives us the spatial part of the linear response: it gives a map of weights that we use for a weighted sum on an image. There are multiple ways of performing this operation: diff --git a/docs/tutorials/plot_05_place_cells.md b/docs/tutorials/plot_05_place_cells.md index 59e81eae..bf7f8f59 100644 --- a/docs/tutorials/plot_05_place_cells.md +++ b/docs/tutorials/plot_05_place_cells.md @@ -119,6 +119,17 @@ for i, n in enumerate(order): plt.yticks([]) ``` +```{code-cell} ipython3 +:tags: [hide-input] + +# save image for thumbnail +from pathlib import Path + +path = Path("../assets/thumbnails/tutorials") +if path.exists(): + plt.savefig(path / "plot_05_place_cells.svg") +``` + ## Phase precession In addition to place modulation, place cells are also modulated by the theta oscillation. The phase at which neurons fire is dependant of the position. This phenomen is called "phase precession" (see [J. O’Keefe, M. L. Recce, "Phase relationship between hippocampal place units and the EEG theta rhythm." Hippocampus 3, 317–330 (1993).](https://doi.org/10.1002/hipo.450030307)). diff --git a/docs/tutorials/plot_06_calcium_imaging.md b/docs/tutorials/plot_06_calcium_imaging.md index 151c6d74..dec3031d 100644 --- a/docs/tutorials/plot_06_calcium_imaging.md +++ b/docs/tutorials/plot_06_calcium_imaging.md @@ -331,6 +331,18 @@ plt.xlabel("Head-direction (rad)") plt.show() ``` +```{code-cell} ipython3 +:tags: [hide-input] + +# save image for thumbnail +from pathlib import Path + +path = Path("../assets/thumbnails/tutorials") +if path.exists(): + plt.savefig(path / "plot_06_calcium_imaging.svg") +``` + + :::{admonition} Gamma-GLM for Calcium Imaging Analysis :class: note From 3625d91980ee3acc0adbc9d1dbfaec628b12b528 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 16:42:50 -0500 Subject: [PATCH 066/107] hide mpl inline --- docs/background/plot_01_1D_basis_function.md | 2 ++ docs/background/plot_02_ND_basis_function.md | 2 ++ docs/how_to_guide/plot_02_glm_demo.md | 2 ++ docs/how_to_guide/plot_03_population_glm.md | 2 ++ docs/how_to_guide/plot_04_batch_glm.md | 2 ++ docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md | 2 ++ docs/how_to_guide/plot_06_glm_pytree.md | 2 ++ docs/tutorials/plot_01_current_injection.md | 2 ++ docs/tutorials/plot_02_head_direction.md | 2 ++ docs/tutorials/plot_03_grid_cells.md | 2 ++ docs/tutorials/plot_04_v1_cells.md | 2 ++ docs/tutorials/plot_05_place_cells.md | 2 ++ docs/tutorials/plot_06_calcium_imaging.md | 2 ++ 13 files changed, 26 insertions(+) diff --git a/docs/background/plot_01_1D_basis_function.md b/docs/background/plot_01_1D_basis_function.md index c092ebcb..49596073 100644 --- a/docs/background/plot_01_1D_basis_function.md +++ b/docs/background/plot_01_1D_basis_function.md @@ -12,6 +12,8 @@ kernelspec: --- ```{code-cell} ipython3 +:tags: [hide-input] + %matplotlib inline ``` diff --git a/docs/background/plot_02_ND_basis_function.md b/docs/background/plot_02_ND_basis_function.md index 1d43ab00..243fa930 100644 --- a/docs/background/plot_02_ND_basis_function.md +++ b/docs/background/plot_02_ND_basis_function.md @@ -12,6 +12,8 @@ kernelspec: --- ```{code-cell} ipython3 +:tags: [hide-input] + %matplotlib inline ``` diff --git a/docs/how_to_guide/plot_02_glm_demo.md b/docs/how_to_guide/plot_02_glm_demo.md index 63469838..ffe2b15d 100644 --- a/docs/how_to_guide/plot_02_glm_demo.md +++ b/docs/how_to_guide/plot_02_glm_demo.md @@ -12,6 +12,8 @@ kernelspec: --- ```{code-cell} ipython3 +:tags: [hide-input] + %matplotlib inline ``` diff --git a/docs/how_to_guide/plot_03_population_glm.md b/docs/how_to_guide/plot_03_population_glm.md index 41c609e7..70288a9d 100644 --- a/docs/how_to_guide/plot_03_population_glm.md +++ b/docs/how_to_guide/plot_03_population_glm.md @@ -12,6 +12,8 @@ kernelspec: --- ```{code-cell} ipython3 +:tags: [hide-input] + %matplotlib inline ``` diff --git a/docs/how_to_guide/plot_04_batch_glm.md b/docs/how_to_guide/plot_04_batch_glm.md index 352ea68d..9a557c77 100644 --- a/docs/how_to_guide/plot_04_batch_glm.md +++ b/docs/how_to_guide/plot_04_batch_glm.md @@ -12,6 +12,8 @@ kernelspec: --- ```{code-cell} ipython3 +:tags: [hide-input] + %matplotlib inline ``` diff --git a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md index 8563db68..c4e8eb14 100644 --- a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md +++ b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md @@ -12,6 +12,8 @@ kernelspec: --- ```{code-cell} ipython3 +:tags: [hide-input] + %matplotlib inline ``` diff --git a/docs/how_to_guide/plot_06_glm_pytree.md b/docs/how_to_guide/plot_06_glm_pytree.md index a0b38b18..9fdd36c5 100644 --- a/docs/how_to_guide/plot_06_glm_pytree.md +++ b/docs/how_to_guide/plot_06_glm_pytree.md @@ -12,6 +12,8 @@ kernelspec: --- ```{code-cell} ipython3 +:tags: [hide-input] + %matplotlib inline ``` diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md index 74e58589..559cf30d 100644 --- a/docs/tutorials/plot_01_current_injection.md +++ b/docs/tutorials/plot_01_current_injection.md @@ -12,6 +12,8 @@ kernelspec: --- ```{code-cell} ipython3 +:tags: [hide-input] + %matplotlib inline ``` diff --git a/docs/tutorials/plot_02_head_direction.md b/docs/tutorials/plot_02_head_direction.md index 64114d90..f746a761 100644 --- a/docs/tutorials/plot_02_head_direction.md +++ b/docs/tutorials/plot_02_head_direction.md @@ -12,6 +12,8 @@ kernelspec: --- ```{code-cell} ipython3 +:tags: [hide-input] + %matplotlib inline ``` diff --git a/docs/tutorials/plot_03_grid_cells.md b/docs/tutorials/plot_03_grid_cells.md index 45f42e46..6b3db4ea 100644 --- a/docs/tutorials/plot_03_grid_cells.md +++ b/docs/tutorials/plot_03_grid_cells.md @@ -12,6 +12,8 @@ kernelspec: --- ```{code-cell} ipython3 +:tags: [hide-input] + %matplotlib inline ``` diff --git a/docs/tutorials/plot_04_v1_cells.md b/docs/tutorials/plot_04_v1_cells.md index 5505dc3e..cfcb7aee 100644 --- a/docs/tutorials/plot_04_v1_cells.md +++ b/docs/tutorials/plot_04_v1_cells.md @@ -12,6 +12,8 @@ kernelspec: --- ```{code-cell} ipython3 +:tags: [hide-input] + %matplotlib inline ``` diff --git a/docs/tutorials/plot_05_place_cells.md b/docs/tutorials/plot_05_place_cells.md index bf7f8f59..e983d84c 100644 --- a/docs/tutorials/plot_05_place_cells.md +++ b/docs/tutorials/plot_05_place_cells.md @@ -12,6 +12,8 @@ kernelspec: --- ```{code-cell} ipython3 +:tags: [hide-input] + %matplotlib inline ``` diff --git a/docs/tutorials/plot_06_calcium_imaging.md b/docs/tutorials/plot_06_calcium_imaging.md index dec3031d..aaedbba9 100644 --- a/docs/tutorials/plot_06_calcium_imaging.md +++ b/docs/tutorials/plot_06_calcium_imaging.md @@ -12,6 +12,8 @@ kernelspec: --- ```{code-cell} ipython3 +:tags: [hide-input] + %matplotlib inline ``` From d9ad0c726a06ee8393fcbc4ccf8e5d981a41eda1 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 17:04:35 -0500 Subject: [PATCH 067/107] added all thumbnails --- .../background/plot_01_1D_basis_function.svg | 52 +- .../background/plot_02_ND_basis_function.svg | 398 +- .../background/plot_03_1D_convolution.svg | 692 +- .../tutorials/plot_01_current_injection.svg | 5304 +- .../tutorials/plot_02_head_direction.svg | 49292 +++++++++++++++- .../tutorials/plot_03_grid_cells.svg | 1326 +- .../thumbnails/tutorials/plot_04_v1_cells.svg | 366 +- .../tutorials/plot_05_place_cells.svg | 14809 ++++- .../tutorials/plot_06_calcium_imaging.svg | 1400 +- docs/background/README.md | 6 +- docs/background/plot_01_1D_basis_function.md | 2 +- docs/background/plot_02_ND_basis_function.md | 2 +- docs/background/plot_03_1D_convolution.md | 2 +- docs/how_to_guide/README.md | 25 + docs/how_to_guide/plot_02_glm_demo.md | 14 +- docs/how_to_guide/plot_03_population_glm.md | 11 + docs/how_to_guide/plot_04_batch_glm.md | 13 +- .../plot_05_sklearn_pipeline_cv_demo.md | 11 + docs/how_to_guide/plot_06_glm_pytree.md | 12 + docs/tutorials/README.md | 33 +- docs/tutorials/plot_01_current_injection.md | 4 +- docs/tutorials/plot_02_head_direction.md | 28 +- docs/tutorials/plot_03_grid_cells.md | 2 +- docs/tutorials/plot_04_v1_cells.md | 2 +- docs/tutorials/plot_05_place_cells.md | 4 +- docs/tutorials/plot_06_calcium_imaging.md | 4 +- src/nemos/_documentation_utils/plotting.py | 1 + 27 files changed, 73186 insertions(+), 629 deletions(-) diff --git a/docs/assets/thumbnails/background/plot_01_1D_basis_function.svg b/docs/assets/thumbnails/background/plot_01_1D_basis_function.svg index 434ecd38..444bc65b 100644 --- a/docs/assets/thumbnails/background/plot_01_1D_basis_function.svg +++ b/docs/assets/thumbnails/background/plot_01_1D_basis_function.svg @@ -6,7 +6,7 @@ - 2024-11-21T16:22:50.988028 + 2024-11-21T16:55:09.616385 image/svg+xml @@ -41,12 +41,12 @@ z - - + @@ -82,7 +82,7 @@ z - + @@ -123,7 +123,7 @@ z - + @@ -159,7 +159,7 @@ z - + @@ -206,7 +206,7 @@ z - + @@ -262,7 +262,7 @@ z - + @@ -296,12 +296,12 @@ z - - + @@ -325,7 +325,7 @@ z - + @@ -340,7 +340,7 @@ z - + @@ -355,7 +355,7 @@ z - + @@ -370,7 +370,7 @@ z - + @@ -385,7 +385,7 @@ z - + @@ -428,7 +428,7 @@ L 117.336436 295.430344 L 120.258327 295.488 L 398.487273 295.488 L 398.487273 295.488 -" clip-path="url(#p89432daa2a)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3cac1793bf)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3cac1793bf)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3cac1793bf)" style="fill: none; stroke: #2ca02c; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3cac1793bf)" style="fill: none; stroke: #d62728; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3cac1793bf)" style="fill: none; stroke: #9467bd; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3cac1793bf)" style="fill: none; stroke: #8c564b; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3cac1793bf)" style="fill: none; stroke: #e377c2; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3cac1793bf)" style="fill: none; stroke: #7f7f7f; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3cac1793bf)" style="fill: none; stroke: #bcbd22; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3cac1793bf)" style="fill: none; stroke: #17becf; stroke-width: 1.5; stroke-linecap: square"/> + diff --git a/docs/assets/thumbnails/background/plot_02_ND_basis_function.svg b/docs/assets/thumbnails/background/plot_02_ND_basis_function.svg index 0309ad44..5319c017 100644 --- a/docs/assets/thumbnails/background/plot_02_ND_basis_function.svg +++ b/docs/assets/thumbnails/background/plot_02_ND_basis_function.svg @@ -6,7 +6,7 @@ - 2024-11-21T16:22:58.262336 + 2024-11-21T16:54:57.698785 image/svg+xml @@ -41,12 +41,12 @@ z - - + @@ -92,7 +92,7 @@ z - + @@ -159,7 +159,7 @@ z - + @@ -175,7 +175,7 @@ z - + @@ -203,7 +203,7 @@ z - + @@ -237,12 +237,12 @@ z - - + @@ -255,7 +255,7 @@ L -3.5 0 - + @@ -269,7 +269,7 @@ L -3.5 0 - + @@ -317,7 +317,7 @@ L 47.556612 105.460908 L 47.971858 105.561818 L 175.591026 105.561818 L 175.591026 105.561818 -" clip-path="url(#p6f21f90f7d)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6b88df229e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6b88df229e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6b88df229e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6b88df229e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6b88df229e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6b88df229e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6b88df229e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6b88df229e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6b88df229e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6b88df229e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6b88df229e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6b88df229e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6b88df229e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6b88df229e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6b88df229e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6b88df229e)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> - + @@ -921,7 +921,7 @@ z - + @@ -937,7 +937,7 @@ z - + @@ -953,7 +953,7 @@ z - + @@ -969,7 +969,7 @@ z - + @@ -987,7 +987,7 @@ z - + @@ -1002,7 +1002,7 @@ z - + @@ -1017,7 +1017,7 @@ z - + @@ -1039,7 +1039,7 @@ L 230.460819 105.210754 L 230.599234 105.561818 L 366.938584 105.561818 L 366.938584 105.561818 -" clip-path="url(#p08db2c7c11)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ac224510e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ac224510e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ac224510e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ac224510e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ac224510e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ac224510e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ac224510e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ac224510e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ac224510e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ac224510e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ac224510e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ac224510e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ac224510e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ac224510e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ac224510e)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe02413c669)" style="fill: #eaf3fb"/> +" clip-path="url(#pe02413c669)" style="fill: #d2e3f3"/> +" clip-path="url(#pe02413c669)" style="fill: #b2d2e8"/> +" clip-path="url(#pe02413c669)" style="fill: #84bcdb"/> +" clip-path="url(#pe02413c669)" style="fill: #56a0ce"/> +" clip-path="url(#pe02413c669)" style="fill: #3181bd"/> +" clip-path="url(#pe02413c669)" style="fill: #1460a8"/> +" clip-path="url(#pe02413c669)" style="fill: #084082"/> - + @@ -2506,7 +2506,7 @@ z - + @@ -2521,7 +2521,7 @@ z - + @@ -2659,7 +2659,7 @@ z - + @@ -2675,7 +2675,7 @@ z - + @@ -2691,7 +2691,7 @@ z - + @@ -2707,7 +2707,7 @@ z - + @@ -2723,7 +2723,7 @@ z - + @@ -2873,7 +2873,7 @@ z - + @@ -2889,7 +2889,7 @@ z - + @@ -2905,7 +2905,7 @@ z - + @@ -2921,7 +2921,7 @@ z - + @@ -2937,7 +2937,7 @@ z - + @@ -2955,7 +2955,7 @@ z - + @@ -2968,7 +2968,7 @@ z - + @@ -2982,7 +2982,7 @@ z - + @@ -3009,7 +3009,7 @@ L 47.556612 245.860908 L 47.971858 245.961818 L 175.591026 245.961818 L 175.591026 245.961818 -" clip-path="url(#pc0b9ab3b5b)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7f40d74a2f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7f40d74a2f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7f40d74a2f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7f40d74a2f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7f40d74a2f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7f40d74a2f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7f40d74a2f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7f40d74a2f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7f40d74a2f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7f40d74a2f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7f40d74a2f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7f40d74a2f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7f40d74a2f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7f40d74a2f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7f40d74a2f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7f40d74a2f)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> - + @@ -3552,7 +3552,7 @@ z - + @@ -3568,7 +3568,7 @@ z - + @@ -3584,7 +3584,7 @@ z - + @@ -3600,7 +3600,7 @@ z - + @@ -3618,7 +3618,7 @@ z - + @@ -3633,7 +3633,7 @@ z - + @@ -3648,7 +3648,7 @@ z - + @@ -3670,7 +3670,7 @@ L 230.460819 245.610754 L 230.599234 245.961818 L 366.938584 245.961818 L 366.938584 245.961818 -" clip-path="url(#pdb1aa6aeec)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2422546ea9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2422546ea9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2422546ea9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2422546ea9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2422546ea9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2422546ea9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2422546ea9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2422546ea9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2422546ea9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2422546ea9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2422546ea9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2422546ea9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2422546ea9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2422546ea9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2422546ea9)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p178f756ea9)" style="fill: #e9f2fa"/> +" clip-path="url(#p178f756ea9)" style="fill: #cde0f1"/> +" clip-path="url(#p178f756ea9)" style="fill: #a4cce3"/> +" clip-path="url(#p178f756ea9)" style="fill: #6aaed6"/> +" clip-path="url(#p178f756ea9)" style="fill: #3d8dc4"/> +" clip-path="url(#p178f756ea9)" style="fill: #1967ad"/> +" clip-path="url(#p178f756ea9)" style="fill: #084387"/> - + @@ -5420,7 +5420,7 @@ z - + @@ -5435,7 +5435,7 @@ z - + @@ -5464,7 +5464,7 @@ z - + @@ -5480,7 +5480,7 @@ z - + @@ -5496,7 +5496,7 @@ z - + @@ -5512,7 +5512,7 @@ z - + @@ -5528,7 +5528,7 @@ z - + @@ -5613,7 +5613,7 @@ z - + @@ -5629,7 +5629,7 @@ z - + @@ -5645,7 +5645,7 @@ z - + @@ -5661,7 +5661,7 @@ z - + @@ -5677,7 +5677,7 @@ z - + @@ -5707,7 +5707,7 @@ z - + @@ -5720,7 +5720,7 @@ z - + @@ -5734,7 +5734,7 @@ z - + @@ -5761,7 +5761,7 @@ L 47.556612 386.260908 L 47.971858 386.361818 L 175.591026 386.361818 L 175.591026 386.361818 -" clip-path="url(#p236ff53f89)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfbd98fe1b9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfbd98fe1b9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfbd98fe1b9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfbd98fe1b9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfbd98fe1b9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfbd98fe1b9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfbd98fe1b9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfbd98fe1b9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfbd98fe1b9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfbd98fe1b9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfbd98fe1b9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfbd98fe1b9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfbd98fe1b9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfbd98fe1b9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfbd98fe1b9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfbd98fe1b9)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> - + @@ -6302,7 +6302,7 @@ z - + @@ -6318,7 +6318,7 @@ z - + @@ -6334,7 +6334,7 @@ z - + @@ -6350,7 +6350,7 @@ z - + @@ -6380,7 +6380,7 @@ z - + @@ -6395,7 +6395,7 @@ z - + @@ -6410,7 +6410,7 @@ z - + @@ -6432,7 +6432,7 @@ L 230.460819 386.010754 L 230.599234 386.361818 L 366.938584 386.361818 L 366.938584 386.361818 -" clip-path="url(#p5842bf64d7)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa3bac129c)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa3bac129c)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa3bac129c)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa3bac129c)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa3bac129c)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa3bac129c)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa3bac129c)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa3bac129c)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa3bac129c)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa3bac129c)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa3bac129c)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa3bac129c)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa3bac129c)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa3bac129c)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa3bac129c)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3eb4cf63e5)" style="fill: #e9f2fa"/> +" clip-path="url(#p3eb4cf63e5)" style="fill: #cde0f1"/> +" clip-path="url(#p3eb4cf63e5)" style="fill: #a4cce3"/> +" clip-path="url(#p3eb4cf63e5)" style="fill: #6aaed6"/> +" clip-path="url(#p3eb4cf63e5)" style="fill: #3d8dc4"/> +" clip-path="url(#p3eb4cf63e5)" style="fill: #1967ad"/> +" clip-path="url(#p3eb4cf63e5)" style="fill: #084387"/> - + @@ -8403,7 +8403,7 @@ z - + @@ -8418,7 +8418,7 @@ z - + @@ -8447,7 +8447,7 @@ z - + @@ -8463,7 +8463,7 @@ z - + @@ -8479,7 +8479,7 @@ z - + @@ -8495,7 +8495,7 @@ z - + @@ -8511,7 +8511,7 @@ z - + @@ -8587,31 +8587,31 @@ L 529.607558 309.12 - + - + - + - + - + - + - + - + - + diff --git a/docs/assets/thumbnails/background/plot_03_1D_convolution.svg b/docs/assets/thumbnails/background/plot_03_1D_convolution.svg index 3de128d6..6a232e04 100644 --- a/docs/assets/thumbnails/background/plot_03_1D_convolution.svg +++ b/docs/assets/thumbnails/background/plot_03_1D_convolution.svg @@ -6,7 +6,7 @@ - 2024-11-21T16:23:04.671790 + 2024-11-21T16:55:32.887616 image/svg+xml @@ -43,18 +43,18 @@ L 97.982668 83.350909 L 97.982668 29.569091 L 63.579545 29.569091 z -" clip-path="url(#p8b105a05eb)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> - - + @@ -90,7 +90,7 @@ z - + @@ -130,7 +130,7 @@ z - + @@ -165,7 +165,7 @@ z - + @@ -211,7 +211,7 @@ z - + @@ -266,7 +266,7 @@ z - + @@ -299,12 +299,12 @@ z - - + @@ -361,7 +361,7 @@ z - + @@ -376,7 +376,7 @@ z - + @@ -519,304 +519,304 @@ z +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3b8ef6b55b)" style="fill: none; stroke: #2ca02c; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8e1369496b)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> - + @@ -1291,7 +1291,7 @@ z - + @@ -1305,7 +1305,7 @@ z - + @@ -1319,7 +1319,7 @@ z - + @@ -1333,7 +1333,7 @@ z - + @@ -1347,7 +1347,7 @@ z - + @@ -1364,7 +1364,7 @@ z - + @@ -1380,7 +1380,7 @@ z - + @@ -1395,7 +1395,7 @@ z - + @@ -1450,304 +1450,304 @@ z +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8e1369496b)" style="fill: none; stroke: #2ca02c; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> - + @@ -2091,7 +2091,7 @@ z - + @@ -2105,7 +2105,7 @@ z - + @@ -2119,7 +2119,7 @@ z - + @@ -2133,7 +2133,7 @@ z - + @@ -2147,7 +2147,7 @@ z - + @@ -2164,7 +2164,7 @@ z - + @@ -2180,7 +2180,7 @@ z - + @@ -2195,7 +2195,7 @@ z - + @@ -2223,304 +2223,304 @@ z +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4f2c1bfc46)" style="fill: none; stroke: #2ca02c; stroke-width: 1.5; stroke-linecap: square"/> + - + - + diff --git a/docs/assets/thumbnails/tutorials/plot_01_current_injection.svg b/docs/assets/thumbnails/tutorials/plot_01_current_injection.svg index f106703f..1831dc9c 100644 --- a/docs/assets/thumbnails/tutorials/plot_01_current_injection.svg +++ b/docs/assets/thumbnails/tutorials/plot_01_current_injection.svg @@ -1,12 +1,12 @@ - + - 2024-11-21T16:39:51.482044 + 2024-11-21T16:48:53.270803 image/svg+xml @@ -21,12 +21,5306 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/thumbnails/tutorials/plot_02_head_direction.svg b/docs/assets/thumbnails/tutorials/plot_02_head_direction.svg index b0fdfa87..7abf409c 100644 --- a/docs/assets/thumbnails/tutorials/plot_02_head_direction.svg +++ b/docs/assets/thumbnails/tutorials/plot_02_head_direction.svg @@ -1,12 +1,12 @@ - + - 2024-11-21T16:40:15.985300 + 2024-11-21T16:53:28.188205 image/svg+xml @@ -21,12 +21,49294 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/thumbnails/tutorials/plot_03_grid_cells.svg b/docs/assets/thumbnails/tutorials/plot_03_grid_cells.svg index 43758eef..45f53800 100644 --- a/docs/assets/thumbnails/tutorials/plot_03_grid_cells.svg +++ b/docs/assets/thumbnails/tutorials/plot_03_grid_cells.svg @@ -1,12 +1,12 @@ - + - 2024-11-21T16:39:35.168729 + 2024-11-21T16:50:14.287475 image/svg+xml @@ -21,12 +21,1328 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg b/docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg index 3953ccb7..963d4728 100644 --- a/docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg +++ b/docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg @@ -1,12 +1,12 @@ - + - 2024-11-21T16:39:08.264295 + 2024-11-21T16:50:35.154043 image/svg+xml @@ -21,12 +21,368 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/thumbnails/tutorials/plot_05_place_cells.svg b/docs/assets/thumbnails/tutorials/plot_05_place_cells.svg index 684518bf..b95331b7 100644 --- a/docs/assets/thumbnails/tutorials/plot_05_place_cells.svg +++ b/docs/assets/thumbnails/tutorials/plot_05_place_cells.svg @@ -1,12 +1,12 @@ - + - 2024-11-21T16:38:04.234838 + 2024-11-21T16:50:55.081995 image/svg+xml @@ -21,12 +21,14811 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg b/docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg index d48562d5..369982b1 100644 --- a/docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg +++ b/docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg @@ -6,7 +6,7 @@ - 2024-11-21T16:38:30.602908 + 2024-11-21T16:53:44.508011 image/svg+xml @@ -28,5 +28,1403 @@ L 0 0 z " style="fill: #ffffff"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/background/README.md b/docs/background/README.md index 10658243..13e7b3a7 100644 --- a/docs/background/README.md +++ b/docs/background/README.md @@ -34,7 +34,7 @@ plot_00_conceptual_intro.md :::{grid-item-card}
-Linear-Non Linear-Poisson illustration. +One-Dimensional Basis.
```{toctree} @@ -47,7 +47,7 @@ plot_01_1D_basis_function.md :::{grid-item-card}
-Linear-Non Linear-Poisson illustration. +N-Dimensional Basis.
```{toctree} @@ -60,7 +60,7 @@ plot_02_ND_basis_function.md :::{grid-item-card}
-Linear-Non Linear-Poisson illustration. +One-Dimensional Convolutions.
```{toctree} diff --git a/docs/background/plot_01_1D_basis_function.md b/docs/background/plot_01_1D_basis_function.md index 49596073..6c7d3a62 100644 --- a/docs/background/plot_01_1D_basis_function.md +++ b/docs/background/plot_01_1D_basis_function.md @@ -74,7 +74,7 @@ from pathlib import Path path = Path("../assets/thumbnails/background") if path.exists(): - fig.savefig(path / "one_dim_bspline_basis.svg") + fig.savefig(path / "plot_01_1D_basis_function.svg") ``` ## Setting the basis support diff --git a/docs/background/plot_02_ND_basis_function.md b/docs/background/plot_02_ND_basis_function.md index 243fa930..8e62d7f6 100644 --- a/docs/background/plot_02_ND_basis_function.md +++ b/docs/background/plot_02_ND_basis_function.md @@ -278,7 +278,7 @@ from pathlib import Path path = Path("../assets/thumbnails/background") if path.exists(): - fig.savefig(path / "multiplicative_basis.svg") + fig.savefig(path / "plot_02_ND_basis_function.svg") ``` :::{info} diff --git a/docs/background/plot_03_1D_convolution.md b/docs/background/plot_03_1D_convolution.md index 012b07ae..f2a07688 100644 --- a/docs/background/plot_03_1D_convolution.md +++ b/docs/background/plot_03_1D_convolution.md @@ -149,7 +149,7 @@ from pathlib import Path path = Path("../assets/thumbnails/background") if path.exists(): - fig.savefig(path / "convolutions_valid_mode.svg") + fig.savefig(path / "plot_03_1D_convolution.svg") ``` ## Convolve using [`Basis.compute_features`](nemos.basis.Basis.compute_features) diff --git a/docs/how_to_guide/README.md b/docs/how_to_guide/README.md index 188fe5b2..af6107b6 100644 --- a/docs/how_to_guide/README.md +++ b/docs/how_to_guide/README.md @@ -17,6 +17,11 @@ pip install nemos[examples] ::::{grid} 1 2 3 3 :::{grid-item-card} + +
+Place cells. +
+ ```{toctree} :maxdepth: 2 @@ -25,6 +30,11 @@ plot_02_glm_demo.md ::: :::{grid-item-card} + +
+Place cells. +
+ ```{toctree} :maxdepth: 2 @@ -33,6 +43,11 @@ plot_03_population_glm.md ::: :::{grid-item-card} + +
+Place cells. +
+ ```{toctree} :maxdepth: 2 @@ -41,6 +56,11 @@ plot_04_batch_glm.md ::: :::{grid-item-card} + +
+Place cells. +
+ ```{toctree} :maxdepth: 2 @@ -49,6 +69,11 @@ plot_05_sklearn_pipeline_cv_demo.md ::: :::{grid-item-card} + +
+Place cells. +
+ ```{toctree} :maxdepth: 2 diff --git a/docs/how_to_guide/plot_02_glm_demo.md b/docs/how_to_guide/plot_02_glm_demo.md index ffe2b15d..72bb28fa 100644 --- a/docs/how_to_guide/plot_02_glm_demo.md +++ b/docs/how_to_guide/plot_02_glm_demo.md @@ -391,7 +391,7 @@ And finally plot the results for both neurons. ```{code-cell} ipython3 # mkdocs_gallery_thumbnail_number = 4 -plt.figure() +fig = plt.figure() ax = plt.subplot(111) ax.spines['top'].set_visible(False) @@ -411,5 +411,17 @@ plt.ylabel("count/bin") plt.legend() ``` +```{code-cell} ipython3 +:tags: [hide-input] + +# save image for thumbnail +from pathlib import Path + +path = Path("../assets/thumbnails/how_to_guide") +if path.exists(): + fig.savefig(path / "plot_02_glm_demo.svg") +``` + + ## References [1] Arribas, Diego, Yuan Zhao, and Il Memming Park. "Rescuing neural spike train models from bad MLE." Advances in Neural Information Processing Systems 33 (2020): 2293-2303. diff --git a/docs/how_to_guide/plot_03_population_glm.md b/docs/how_to_guide/plot_03_population_glm.md index 70288a9d..827da40e 100644 --- a/docs/how_to_guide/plot_03_population_glm.md +++ b/docs/how_to_guide/plot_03_population_glm.md @@ -192,6 +192,17 @@ for neuron in range(2): plt.tight_layout() ``` +```{code-cell} ipython3 +:tags: [hide-input] + +# save image for thumbnail +from pathlib import Path + +path = Path("../assets/thumbnails/how_to_guide") +if path.exists(): + fig.savefig(path / "plot_03_population_glm.svg") +``` + ## FeaturePytree [`PopulationGLM`](nemos.glm.PopulationGLM) is compatible with [`FeaturePytree`](nemos.pytrees.FeaturePytree). If you structured your predictors in a [`FeaturePytree`](nemos.pytrees.FeaturePytree), the `feature_mask` needs to be a dictionary of the same structure, containing arrays diff --git a/docs/how_to_guide/plot_04_batch_glm.md b/docs/how_to_guide/plot_04_batch_glm.md index 9a557c77..7043d745 100644 --- a/docs/how_to_guide/plot_04_batch_glm.md +++ b/docs/how_to_guide/plot_04_batch_glm.md @@ -163,13 +163,24 @@ First let's plot the log-likelihood to see if the model is converging. ```{code-cell} ipython3 -plt.figure() +fig = plt.figure() plt.plot(logl) plt.xlabel("Iteration") plt.ylabel("Log-likelihood") plt.show() ``` +```{code-cell} ipython3 +:tags: [hide-input] + +# save image for thumbnail +from pathlib import Path + +path = Path("../assets/thumbnails/how_to_guide") +if path.exists(): + fig.savefig(path / "plot_04_batch_glm.svg") +``` + We can see that the log-likelihood is increasing but did not reach plateau yet. The number of iterations can be increased to continue learning. diff --git a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md index c4e8eb14..4a91b4f8 100644 --- a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md +++ b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md @@ -393,6 +393,17 @@ ax.legend() sns.despine(ax=ax) ``` +```{code-cell} ipython3 +:tags: [hide-input] + +# save image for thumbnail +from pathlib import Path + +path = Path("../assets/thumbnails/how_to_guide") +if path.exists(): + fig.savefig(path / "plot_05_sklearn_pipeline_cv_demo.svg") +``` + :rocket::rocket::rocket: **Success!** :rocket::rocket::rocket: We are now able to capture the distribution of the firing rate appropriately: both peaks and valleys in the spiking activity are matched by our model predicitons. diff --git a/docs/how_to_guide/plot_06_glm_pytree.md b/docs/how_to_guide/plot_06_glm_pytree.md index 9fdd36c5..c613b605 100644 --- a/docs/how_to_guide/plot_06_glm_pytree.md +++ b/docs/how_to_guide/plot_06_glm_pytree.md @@ -221,6 +221,18 @@ for i, ax in zip(tune_head.columns, axes.flatten()): axes[-1,-1].remove() ``` +```{code-cell} ipython3 +:tags: [hide-input] + +# save image for thumbnail +from pathlib import Path + +path = Path("../assets/thumbnails/how_to_guide") +if path.exists(): + fig.savefig(path / "plot_06_glm_pytree.svg") +``` + + Okay, let's use unit number 7. Now let's set up our design matrix. First, let's fit the head direction by diff --git a/docs/tutorials/README.md b/docs/tutorials/README.md index 5dffd196..5dde4e54 100644 --- a/docs/tutorials/README.md +++ b/docs/tutorials/README.md @@ -15,6 +15,11 @@ pip install nemos[examples] ::::{grid} 1 2 3 3 :::{grid-item-card} + +
+Current Injection. +
+ ```{toctree} :maxdepth: 2 @@ -23,6 +28,11 @@ plot_01_current_injection.md ::: :::{grid-item-card} + +
+Head direction. +
+ ```{toctree} :maxdepth: 2 @@ -31,15 +41,25 @@ plot_02_head_direction.md ::: :::{grid-item-card} + +
+Grid Cells. +
+ ```{toctree} :maxdepth: 2 plot_03_grid_cells.md ``` -::: +::: :::{grid-item-card} + +
+V1 cells. +
+ ```{toctree} :maxdepth: 2 @@ -47,8 +67,12 @@ plot_04_v1_cells.md ``` ::: - :::{grid-item-card} + +
+Place cells. +
+ ```{toctree} :maxdepth: 2 @@ -57,6 +81,11 @@ plot_05_place_cells.md ::: :::{grid-item-card} + +
+Calcium immaging. +
+ ```{toctree} :maxdepth: 2 plot_06_calcium_imaging.md diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md index 559cf30d..50890639 100644 --- a/docs/tutorials/plot_01_current_injection.md +++ b/docs/tutorials/plot_01_current_injection.md @@ -589,7 +589,7 @@ predicted_fr = predicted_fr / bin_size smooth_predicted_fr = predicted_fr.smooth(0.05, size_factor=20) # and plot! -doc_plots.current_injection_plot(current, spikes, firing_rate, +fig = doc_plots.current_injection_plot(current, spikes, firing_rate, # plot the predicted firing rate that has # been smoothed the same way as the # smoothed spike train @@ -604,7 +604,7 @@ from pathlib import Path path = Path("../assets/thumbnails/tutorials") if path.exists(): - plt.savefig(path / "plot_01_current_injection.svg") + fig.savefig(path / "plot_01_current_injection.svg") ``` What do we see above? Note that the y-axes in the final row are different for diff --git a/docs/tutorials/plot_02_head_direction.md b/docs/tutorials/plot_02_head_direction.md index f746a761..d1c0291b 100644 --- a/docs/tutorials/plot_02_head_direction.md +++ b/docs/tutorials/plot_02_head_direction.md @@ -634,23 +634,12 @@ Let's see if our firing rate predictions improved and in what sense. ```{code-cell} ipython3 # mkdocs_gallery_thumbnail_number = 2 -doc_plots.plot_rates_and_smoothed_counts( +fig = doc_plots.plot_rates_and_smoothed_counts( neuron_count, {"Self-connection: raw history": rate_history, "Self-connection: bsais": rate_basis, "All-to-all: basis": predicted_firing_rate[:, 0]} -); -``` - -```{code-cell} ipython3 -:tags: [hide-input] - -# save image for thumbnail -from pathlib import Path - -path = Path("../assets/thumbnails/tutorials") -if path.exists(): - plt.savefig(path / "plot_02_head_direction.svg") +) ``` #### Visualizing the connectivity @@ -685,5 +674,16 @@ all the coupling filters. ```{code-cell} ipython3 -doc_plots.plot_coupling(responses, tuning); +fig = doc_plots.plot_coupling(responses, tuning) ``` + +```{code-cell} ipython3 +:tags: [hide-input] + +# save image for thumbnail +from pathlib import Path + +path = Path("../assets/thumbnails/tutorials") +if path.exists(): + fig.savefig(path / "plot_02_head_direction.svg") +``` \ No newline at end of file diff --git a/docs/tutorials/plot_03_grid_cells.md b/docs/tutorials/plot_03_grid_cells.md index 6b3db4ea..1ad3806a 100644 --- a/docs/tutorials/plot_03_grid_cells.md +++ b/docs/tutorials/plot_03_grid_cells.md @@ -314,5 +314,5 @@ from pathlib import Path path = Path("../assets/thumbnails/tutorials") if path.exists(): - plt.savefig(path / "plot_03_grid_cells.svg") + fig.savefig(path / "plot_03_grid_cells.svg") ``` \ No newline at end of file diff --git a/docs/tutorials/plot_04_v1_cells.md b/docs/tutorials/plot_04_v1_cells.md index cfcb7aee..8b1f60a5 100644 --- a/docs/tutorials/plot_04_v1_cells.md +++ b/docs/tutorials/plot_04_v1_cells.md @@ -217,7 +217,7 @@ from pathlib import Path path = Path("../assets/thumbnails/tutorials") if path.exists(): - plt.savefig(path / "plot_04_v1_cells.svg") + fig.savefig(path / "plot_04_v1_cells.svg") ``` This receptive field gives us the spatial part of the linear response: it diff --git a/docs/tutorials/plot_05_place_cells.md b/docs/tutorials/plot_05_place_cells.md index e983d84c..55e08186 100644 --- a/docs/tutorials/plot_05_place_cells.md +++ b/docs/tutorials/plot_05_place_cells.md @@ -109,7 +109,7 @@ Here each row is one neuron ```{code-cell} ipython3 -plt.figure(figsize=(12, 10)) +fig = plt.figure(figsize=(12, 10)) gs = plt.GridSpec(len(spikes), 1) for i, n in enumerate(order): plt.subplot(gs[i, 0]) @@ -129,7 +129,7 @@ from pathlib import Path path = Path("../assets/thumbnails/tutorials") if path.exists(): - plt.savefig(path / "plot_05_place_cells.svg") + fig.savefig(path / "plot_05_place_cells.svg") ``` ## Phase precession diff --git a/docs/tutorials/plot_06_calcium_imaging.md b/docs/tutorials/plot_06_calcium_imaging.md index aaedbba9..66c9c451 100644 --- a/docs/tutorials/plot_06_calcium_imaging.md +++ b/docs/tutorials/plot_06_calcium_imaging.md @@ -323,7 +323,7 @@ Let's plot them. ```{code-cell} ipython3 -plt.figure() +fig = plt.figure() plt.plot(real_tcurves[neu], "r", label="true", linewidth=2) plt.plot(gamma_tcurves, "k", label="gamma-nemos", alpha=1) plt.plot(linreg_tcurves, "g", label="linreg-sklearn", alpha=0.5) @@ -341,7 +341,7 @@ from pathlib import Path path = Path("../assets/thumbnails/tutorials") if path.exists(): - plt.savefig(path / "plot_06_calcium_imaging.svg") + fig.savefig(path / "plot_06_calcium_imaging.svg") ``` diff --git a/src/nemos/_documentation_utils/plotting.py b/src/nemos/_documentation_utils/plotting.py index 6072e277..c259e163 100644 --- a/src/nemos/_documentation_utils/plotting.py +++ b/src/nemos/_documentation_utils/plotting.py @@ -292,6 +292,7 @@ def current_injection_plot( bbox_to_anchor=(0.5, -0.4), bbox_transform=zoom_axes[1].transAxes, ) + return fig def plot_weighted_sum_basis(time, weights, basis_kernels, basis_coeff): From b0e91eaa53903bb53505f830629dbd5fcdfe2760 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 17:19:14 -0500 Subject: [PATCH 068/107] added warning ignore filter --- .../background/plot_01_1D_basis_function.svg | 52 +- .../background/plot_02_ND_basis_function.svg | 398 +- .../background/plot_03_1D_convolution.svg | 692 ++-- .../tutorials/plot_01_current_injection.svg | 304 +- .../tutorials/plot_02_head_direction.svg | 3194 ++++++++--------- .../tutorials/plot_03_grid_cells.svg | 96 +- .../thumbnails/tutorials/plot_04_v1_cells.svg | 36 +- .../tutorials/plot_05_place_cells.svg | 458 +-- .../tutorials/plot_06_calcium_imaging.svg | 46 +- docs/background/plot_00_conceptual_intro.md | 23 + docs/background/plot_01_1D_basis_function.md | 23 + docs/background/plot_02_ND_basis_function.md | 23 + docs/background/plot_03_1D_convolution.md | 23 + docs/how_to_guide/plot_02_glm_demo.md | 23 + docs/how_to_guide/plot_03_population_glm.md | 23 + docs/how_to_guide/plot_04_batch_glm.md | 23 + .../plot_05_sklearn_pipeline_cv_demo.md | 23 + docs/how_to_guide/plot_06_glm_pytree.md | 25 + docs/tutorials/plot_01_current_injection.md | 23 + docs/tutorials/plot_02_head_direction.md | 23 + docs/tutorials/plot_03_grid_cells.md | 23 + docs/tutorials/plot_04_v1_cells.md | 23 + docs/tutorials/plot_05_place_cells.md | 23 + docs/tutorials/plot_06_calcium_imaging.md | 23 + 24 files changed, 2985 insertions(+), 2638 deletions(-) diff --git a/docs/assets/thumbnails/background/plot_01_1D_basis_function.svg b/docs/assets/thumbnails/background/plot_01_1D_basis_function.svg index 444bc65b..051f1085 100644 --- a/docs/assets/thumbnails/background/plot_01_1D_basis_function.svg +++ b/docs/assets/thumbnails/background/plot_01_1D_basis_function.svg @@ -6,7 +6,7 @@ - 2024-11-21T16:55:09.616385 + 2024-11-21T17:18:21.319844 image/svg+xml @@ -41,12 +41,12 @@ z - - + @@ -82,7 +82,7 @@ z - + @@ -123,7 +123,7 @@ z - + @@ -159,7 +159,7 @@ z - + @@ -206,7 +206,7 @@ z - + @@ -262,7 +262,7 @@ z - + @@ -296,12 +296,12 @@ z - - + @@ -325,7 +325,7 @@ z - + @@ -340,7 +340,7 @@ z - + @@ -355,7 +355,7 @@ z - + @@ -370,7 +370,7 @@ z - + @@ -385,7 +385,7 @@ z - + @@ -428,7 +428,7 @@ L 117.336436 295.430344 L 120.258327 295.488 L 398.487273 295.488 L 398.487273 295.488 -" clip-path="url(#p3cac1793bf)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa183a60a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa183a60a3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa183a60a3)" style="fill: none; stroke: #2ca02c; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa183a60a3)" style="fill: none; stroke: #d62728; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa183a60a3)" style="fill: none; stroke: #9467bd; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa183a60a3)" style="fill: none; stroke: #8c564b; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa183a60a3)" style="fill: none; stroke: #e377c2; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa183a60a3)" style="fill: none; stroke: #7f7f7f; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa183a60a3)" style="fill: none; stroke: #bcbd22; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa183a60a3)" style="fill: none; stroke: #17becf; stroke-width: 1.5; stroke-linecap: square"/> + diff --git a/docs/assets/thumbnails/background/plot_02_ND_basis_function.svg b/docs/assets/thumbnails/background/plot_02_ND_basis_function.svg index 5319c017..5f358436 100644 --- a/docs/assets/thumbnails/background/plot_02_ND_basis_function.svg +++ b/docs/assets/thumbnails/background/plot_02_ND_basis_function.svg @@ -6,7 +6,7 @@ - 2024-11-21T16:54:57.698785 + 2024-11-21T17:18:28.466348 image/svg+xml @@ -41,12 +41,12 @@ z - - + @@ -92,7 +92,7 @@ z - + @@ -159,7 +159,7 @@ z - + @@ -175,7 +175,7 @@ z - + @@ -203,7 +203,7 @@ z - + @@ -237,12 +237,12 @@ z - - + @@ -255,7 +255,7 @@ L -3.5 0 - + @@ -269,7 +269,7 @@ L -3.5 0 - + @@ -317,7 +317,7 @@ L 47.556612 105.460908 L 47.971858 105.561818 L 175.591026 105.561818 L 175.591026 105.561818 -" clip-path="url(#p6b88df229e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7c2b780cd0)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7c2b780cd0)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7c2b780cd0)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7c2b780cd0)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7c2b780cd0)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7c2b780cd0)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7c2b780cd0)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7c2b780cd0)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7c2b780cd0)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7c2b780cd0)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7c2b780cd0)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7c2b780cd0)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7c2b780cd0)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7c2b780cd0)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7c2b780cd0)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7c2b780cd0)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> - + @@ -921,7 +921,7 @@ z - + @@ -937,7 +937,7 @@ z - + @@ -953,7 +953,7 @@ z - + @@ -969,7 +969,7 @@ z - + @@ -987,7 +987,7 @@ z - + @@ -1002,7 +1002,7 @@ z - + @@ -1017,7 +1017,7 @@ z - + @@ -1039,7 +1039,7 @@ L 230.460819 105.210754 L 230.599234 105.561818 L 366.938584 105.561818 L 366.938584 105.561818 -" clip-path="url(#p8ac224510e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0b3a89a65f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0b3a89a65f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0b3a89a65f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0b3a89a65f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0b3a89a65f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0b3a89a65f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0b3a89a65f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0b3a89a65f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0b3a89a65f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0b3a89a65f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0b3a89a65f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0b3a89a65f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0b3a89a65f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0b3a89a65f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0b3a89a65f)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p64250f0d5a)" style="fill: #eaf3fb"/> +" clip-path="url(#p64250f0d5a)" style="fill: #d2e3f3"/> +" clip-path="url(#p64250f0d5a)" style="fill: #b2d2e8"/> +" clip-path="url(#p64250f0d5a)" style="fill: #84bcdb"/> +" clip-path="url(#p64250f0d5a)" style="fill: #56a0ce"/> +" clip-path="url(#p64250f0d5a)" style="fill: #3181bd"/> +" clip-path="url(#p64250f0d5a)" style="fill: #1460a8"/> +" clip-path="url(#p64250f0d5a)" style="fill: #084082"/> - + @@ -2506,7 +2506,7 @@ z - + @@ -2521,7 +2521,7 @@ z - + @@ -2659,7 +2659,7 @@ z - + @@ -2675,7 +2675,7 @@ z - + @@ -2691,7 +2691,7 @@ z - + @@ -2707,7 +2707,7 @@ z - + @@ -2723,7 +2723,7 @@ z - + @@ -2873,7 +2873,7 @@ z - + @@ -2889,7 +2889,7 @@ z - + @@ -2905,7 +2905,7 @@ z - + @@ -2921,7 +2921,7 @@ z - + @@ -2937,7 +2937,7 @@ z - + @@ -2955,7 +2955,7 @@ z - + @@ -2968,7 +2968,7 @@ z - + @@ -2982,7 +2982,7 @@ z - + @@ -3009,7 +3009,7 @@ L 47.556612 245.860908 L 47.971858 245.961818 L 175.591026 245.961818 L 175.591026 245.961818 -" clip-path="url(#p7f40d74a2f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5450aec2fb)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5450aec2fb)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5450aec2fb)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5450aec2fb)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5450aec2fb)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5450aec2fb)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5450aec2fb)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5450aec2fb)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5450aec2fb)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5450aec2fb)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5450aec2fb)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5450aec2fb)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5450aec2fb)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5450aec2fb)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5450aec2fb)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5450aec2fb)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> - + @@ -3552,7 +3552,7 @@ z - + @@ -3568,7 +3568,7 @@ z - + @@ -3584,7 +3584,7 @@ z - + @@ -3600,7 +3600,7 @@ z - + @@ -3618,7 +3618,7 @@ z - + @@ -3633,7 +3633,7 @@ z - + @@ -3648,7 +3648,7 @@ z - + @@ -3670,7 +3670,7 @@ L 230.460819 245.610754 L 230.599234 245.961818 L 366.938584 245.961818 L 366.938584 245.961818 -" clip-path="url(#p2422546ea9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p48ba903a81)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p48ba903a81)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p48ba903a81)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p48ba903a81)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p48ba903a81)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p48ba903a81)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p48ba903a81)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p48ba903a81)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p48ba903a81)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p48ba903a81)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p48ba903a81)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p48ba903a81)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p48ba903a81)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p48ba903a81)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p48ba903a81)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p915a4ccc4e)" style="fill: #e9f2fa"/> +" clip-path="url(#p915a4ccc4e)" style="fill: #cde0f1"/> +" clip-path="url(#p915a4ccc4e)" style="fill: #a4cce3"/> +" clip-path="url(#p915a4ccc4e)" style="fill: #6aaed6"/> +" clip-path="url(#p915a4ccc4e)" style="fill: #3d8dc4"/> +" clip-path="url(#p915a4ccc4e)" style="fill: #1967ad"/> +" clip-path="url(#p915a4ccc4e)" style="fill: #084387"/> - + @@ -5420,7 +5420,7 @@ z - + @@ -5435,7 +5435,7 @@ z - + @@ -5464,7 +5464,7 @@ z - + @@ -5480,7 +5480,7 @@ z - + @@ -5496,7 +5496,7 @@ z - + @@ -5512,7 +5512,7 @@ z - + @@ -5528,7 +5528,7 @@ z - + @@ -5613,7 +5613,7 @@ z - + @@ -5629,7 +5629,7 @@ z - + @@ -5645,7 +5645,7 @@ z - + @@ -5661,7 +5661,7 @@ z - + @@ -5677,7 +5677,7 @@ z - + @@ -5707,7 +5707,7 @@ z - + @@ -5720,7 +5720,7 @@ z - + @@ -5734,7 +5734,7 @@ z - + @@ -5761,7 +5761,7 @@ L 47.556612 386.260908 L 47.971858 386.361818 L 175.591026 386.361818 L 175.591026 386.361818 -" clip-path="url(#pfbd98fe1b9)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paf9f9b9397)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paf9f9b9397)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paf9f9b9397)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paf9f9b9397)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paf9f9b9397)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paf9f9b9397)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paf9f9b9397)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paf9f9b9397)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paf9f9b9397)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paf9f9b9397)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paf9f9b9397)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paf9f9b9397)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paf9f9b9397)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paf9f9b9397)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paf9f9b9397)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paf9f9b9397)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> - + @@ -6302,7 +6302,7 @@ z - + @@ -6318,7 +6318,7 @@ z - + @@ -6334,7 +6334,7 @@ z - + @@ -6350,7 +6350,7 @@ z - + @@ -6380,7 +6380,7 @@ z - + @@ -6395,7 +6395,7 @@ z - + @@ -6410,7 +6410,7 @@ z - + @@ -6432,7 +6432,7 @@ L 230.460819 386.010754 L 230.599234 386.361818 L 366.938584 386.361818 L 366.938584 386.361818 -" clip-path="url(#paa3bac129c)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p628da7ad66)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p628da7ad66)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p628da7ad66)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p628da7ad66)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p628da7ad66)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p628da7ad66)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p628da7ad66)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p628da7ad66)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p628da7ad66)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p628da7ad66)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p628da7ad66)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p628da7ad66)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p628da7ad66)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p628da7ad66)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p628da7ad66)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfe379e8656)" style="fill: #e9f2fa"/> +" clip-path="url(#pfe379e8656)" style="fill: #cde0f1"/> +" clip-path="url(#pfe379e8656)" style="fill: #a4cce3"/> +" clip-path="url(#pfe379e8656)" style="fill: #6aaed6"/> +" clip-path="url(#pfe379e8656)" style="fill: #3d8dc4"/> +" clip-path="url(#pfe379e8656)" style="fill: #1967ad"/> +" clip-path="url(#pfe379e8656)" style="fill: #084387"/> - + @@ -8403,7 +8403,7 @@ z - + @@ -8418,7 +8418,7 @@ z - + @@ -8447,7 +8447,7 @@ z - + @@ -8463,7 +8463,7 @@ z - + @@ -8479,7 +8479,7 @@ z - + @@ -8495,7 +8495,7 @@ z - + @@ -8511,7 +8511,7 @@ z - + @@ -8587,31 +8587,31 @@ L 529.607558 309.12 - + - + - + - + - + - + - + - + - + diff --git a/docs/assets/thumbnails/background/plot_03_1D_convolution.svg b/docs/assets/thumbnails/background/plot_03_1D_convolution.svg index 6a232e04..1bf9e6ff 100644 --- a/docs/assets/thumbnails/background/plot_03_1D_convolution.svg +++ b/docs/assets/thumbnails/background/plot_03_1D_convolution.svg @@ -6,7 +6,7 @@ - 2024-11-21T16:55:32.887616 + 2024-11-21T17:18:34.739430 image/svg+xml @@ -43,18 +43,18 @@ L 97.982668 83.350909 L 97.982668 29.569091 L 63.579545 29.569091 z -" clip-path="url(#p3b8ef6b55b)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> +" clip-path="url(#pc06ca2decf)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> - - + @@ -90,7 +90,7 @@ z - + @@ -130,7 +130,7 @@ z - + @@ -165,7 +165,7 @@ z - + @@ -211,7 +211,7 @@ z - + @@ -266,7 +266,7 @@ z - + @@ -299,12 +299,12 @@ z - - + @@ -361,7 +361,7 @@ z - + @@ -376,7 +376,7 @@ z - + @@ -519,304 +519,304 @@ z +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc06ca2decf)" style="fill: none; stroke: #2ca02c; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1fd5c3c212)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> - + @@ -1291,7 +1291,7 @@ z - + @@ -1305,7 +1305,7 @@ z - + @@ -1319,7 +1319,7 @@ z - + @@ -1333,7 +1333,7 @@ z - + @@ -1347,7 +1347,7 @@ z - + @@ -1364,7 +1364,7 @@ z - + @@ -1380,7 +1380,7 @@ z - + @@ -1395,7 +1395,7 @@ z - + @@ -1450,304 +1450,304 @@ z +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1fd5c3c212)" style="fill: none; stroke: #2ca02c; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7d95170c7f)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> +" clip-path="url(#p7d95170c7f)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> - + @@ -2091,7 +2091,7 @@ z - + @@ -2105,7 +2105,7 @@ z - + @@ -2119,7 +2119,7 @@ z - + @@ -2133,7 +2133,7 @@ z - + @@ -2147,7 +2147,7 @@ z - + @@ -2164,7 +2164,7 @@ z - + @@ -2180,7 +2180,7 @@ z - + @@ -2195,7 +2195,7 @@ z - + @@ -2223,304 +2223,304 @@ z +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7d95170c7f)" style="fill: none; stroke: #2ca02c; stroke-width: 1.5; stroke-linecap: square"/> + - + - + diff --git a/docs/assets/thumbnails/tutorials/plot_01_current_injection.svg b/docs/assets/thumbnails/tutorials/plot_01_current_injection.svg index 1831dc9c..640e7acb 100644 --- a/docs/assets/thumbnails/tutorials/plot_01_current_injection.svg +++ b/docs/assets/thumbnails/tutorials/plot_01_current_injection.svg @@ -6,7 +6,7 @@ - 2024-11-21T16:48:53.270803 + 2024-11-21T17:17:13.523203 image/svg+xml @@ -43,7 +43,7 @@ L 144.371629 144.845217 L 144.371629 60.48 L 106.353262 60.48 z -" clip-path="url(#p53e2afd50c)" style="fill: #ffcc00; opacity: 0.4; stroke: #ffcc00; stroke-linejoin: miter"/> +" clip-path="url(#p869c68c7ec)" style="fill: #ffcc00; opacity: 0.4; stroke: #ffcc00; stroke-linejoin: miter"/> +" clip-path="url(#p869c68c7ec)" style="fill: #ff8000; opacity: 0.4; stroke: #ff8000; stroke-linejoin: miter"/> +" clip-path="url(#p869c68c7ec)" style="fill: #ff3300; opacity: 0.4; stroke: #ff3300; stroke-linejoin: miter"/> - - + - + - + - + - + - + - + @@ -121,12 +121,12 @@ L 0 3.5 - - + @@ -162,7 +162,7 @@ z - + @@ -203,7 +203,7 @@ z - + @@ -2574,7 +2574,7 @@ L 347.135933 102.001083 L 347.247453 141.010435 L 435.845455 141.010435 L 435.845455 141.010435 -" clip-path="url(#p53e2afd50c)" style="fill: none; stroke: #808080; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p869c68c7ec)" style="fill: none; stroke: #808080; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcc474ca166)" style="fill: #ffcc00; opacity: 0.4; stroke: #ffcc00; stroke-linejoin: miter"/> +" clip-path="url(#pcc474ca166)" style="fill: #ff8000; opacity: 0.4; stroke: #ff8000; stroke-linejoin: miter"/> +" clip-path="url(#pcc474ca166)" style="fill: #ff3300; opacity: 0.4; stroke: #ff3300; stroke-linejoin: miter"/> - + @@ -2786,7 +2786,7 @@ z - + @@ -2801,7 +2801,7 @@ z - + @@ -2828,7 +2828,7 @@ z - + @@ -2843,7 +2843,7 @@ z - + @@ -2899,7 +2899,7 @@ z - + @@ -2914,7 +2914,7 @@ z - + @@ -3063,7 +3063,7 @@ z - + @@ -3076,7 +3076,7 @@ z - + @@ -3090,7 +3090,7 @@ z - + @@ -3130,7 +3130,7 @@ z - + @@ -3519,7 +3519,7 @@ L 347.994704 238.694945 L 348.919849 238.721029 L 435.845455 238.721067 L 435.845455 238.721067 -" clip-path="url(#p5e87139852)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcc474ca166)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcc474ca166)" style="fill: none; stroke: #ff6347; stroke-width: 1.5; stroke-linecap: square"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4022,7 +4022,7 @@ z - + @@ -4076,7 +4076,7 @@ z - + @@ -4091,7 +4091,7 @@ z - + @@ -4106,7 +4106,7 @@ z - + @@ -4136,7 +4136,7 @@ z - + @@ -4160,7 +4160,7 @@ z - + @@ -4175,7 +4175,7 @@ z - + @@ -4190,7 +4190,7 @@ z - + @@ -4205,7 +4205,7 @@ z - + @@ -4243,7 +4243,7 @@ z +" clip-path="url(#pcccbc1b167)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> @@ -4389,7 +4389,7 @@ L 170.292366 294.44427 L 171.26745 304.047457 L 172.660428 317.946596 L 172.660428 317.946596 -" clip-path="url(#pe3054519d6)" style="fill: none; stroke: #ff6347; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcccbc1b167)" style="fill: none; stroke: #ff6347; stroke-width: 1.5; stroke-linecap: square"/> - + @@ -4440,7 +4440,7 @@ z - + @@ -4455,7 +4455,7 @@ z - + @@ -4485,7 +4485,7 @@ z - + @@ -4498,7 +4498,7 @@ z - + @@ -4511,7 +4511,7 @@ z - + @@ -4525,7 +4525,7 @@ z - + @@ -4539,7 +4539,7 @@ z - + @@ -4668,22 +4668,22 @@ L 289.65941 338.308585 L 291.644404 338.34365 L 310.519251 338.343907 L 310.519251 338.343907 -" clip-path="url(#pb229b8438d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3d7d35ba68)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> - - - - - - - - - - - - - + + + + + + + + + + + + + @@ -4776,7 +4776,7 @@ L 307.663647 332.826592 L 308.499434 333.906454 L 310.519251 336.643194 L 310.519251 336.643194 -" clip-path="url(#pb229b8438d)" style="fill: none; stroke: #ff6347; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3d7d35ba68)" style="fill: none; stroke: #ff6347; stroke-width: 1.5; stroke-linecap: square"/> - + @@ -4827,7 +4827,7 @@ z - + @@ -4842,7 +4842,7 @@ z - + @@ -4872,7 +4872,7 @@ z - + @@ -4885,7 +4885,7 @@ z - + @@ -4899,7 +4899,7 @@ z - + @@ -4913,7 +4913,7 @@ z - + @@ -5099,38 +5099,38 @@ L 447.333342 334.796436 L 447.925357 337.225652 L 448.378075 338.40525 L 448.378075 338.40525 -" clip-path="url(#pabcf1b6846)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5a0c7bb1f8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -5282,7 +5282,7 @@ L 446.323433 321.526368 L 448.02983 332.702555 L 448.378075 334.352229 L 448.378075 334.352229 -" clip-path="url(#pabcf1b6846)" style="fill: none; stroke: #ff6347; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5a0c7bb1f8)" style="fill: none; stroke: #ff6347; stroke-width: 1.5; stroke-linecap: square"/> + - + - + - + - + diff --git a/docs/assets/thumbnails/tutorials/plot_02_head_direction.svg b/docs/assets/thumbnails/tutorials/plot_02_head_direction.svg index 7abf409c..7f217316 100644 --- a/docs/assets/thumbnails/tutorials/plot_02_head_direction.svg +++ b/docs/assets/thumbnails/tutorials/plot_02_head_direction.svg @@ -6,7 +6,7 @@ - 2024-11-21T16:53:28.188205 + 2024-11-21T17:17:37.779160 image/svg+xml @@ -43,7 +43,7 @@ L 113.445378 87.755294 L 113.445378 69.12 L 90 69.12 z -" clip-path="url(#pd87d18f3a3)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p12301efd11)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -128,12 +128,12 @@ L 111.570287 80.646993 L 111.840085 80.657057 L 112.109882 80.662992 L 112.379679 80.664939 -" clip-path="url(#pd87d18f3a3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p12301efd11)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p12301efd11)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -151,7 +151,7 @@ L 141.579832 87.755294 L 141.579832 69.12 L 118.134454 69.12 z -" clip-path="url(#p078af33e9e)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> +" clip-path="url(#pd3eb448ffb)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> @@ -236,12 +236,12 @@ L 139.704741 80.675468 L 139.974538 80.669563 L 140.244336 80.666081 L 140.514133 80.664939 -" clip-path="url(#p078af33e9e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd3eb448ffb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd3eb448ffb)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -259,7 +259,7 @@ L 169.714286 87.755294 L 169.714286 69.12 L 146.268908 69.12 z -" clip-path="url(#p89b31d2c2f)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> +" clip-path="url(#p8017432f3e)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> @@ -344,12 +344,12 @@ L 167.839195 80.658153 L 168.108992 80.661958 L 168.378789 80.664202 L 168.648587 80.664939 -" clip-path="url(#p89b31d2c2f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8017432f3e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8017432f3e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -367,7 +367,7 @@ L 197.848739 87.755294 L 197.848739 69.12 L 174.403361 69.12 z -" clip-path="url(#p53872ab281)" style="fill: #ff7d7d; opacity: 0.5; stroke: #ff7d7d; stroke-linejoin: miter"/> +" clip-path="url(#p8abb1002f1)" style="fill: #ff7d7d; opacity: 0.5; stroke: #ff7d7d; stroke-linejoin: miter"/> @@ -452,12 +452,12 @@ L 195.973649 80.651515 L 196.243446 80.659043 L 196.513243 80.663482 L 196.78304 80.664939 -" clip-path="url(#p53872ab281)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8abb1002f1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8abb1002f1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -475,7 +475,7 @@ L 225.983193 87.755294 L 225.983193 69.12 L 202.537815 69.12 z -" clip-path="url(#pb06a0623dc)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> +" clip-path="url(#p8a3b5353c9)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> @@ -560,12 +560,12 @@ L 224.108103 80.667353 L 224.3779 80.665999 L 224.647697 80.665201 L 224.917494 80.664939 -" clip-path="url(#pb06a0623dc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8a3b5353c9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8a3b5353c9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -583,7 +583,7 @@ L 254.117647 87.755294 L 254.117647 69.12 L 230.672269 69.12 z -" clip-path="url(#pf1a14e2ae9)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#p63156f34a4)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -668,12 +668,12 @@ L 252.242556 80.665808 L 252.512354 80.66532 L 252.782151 80.665033 L 253.051948 80.664939 -" clip-path="url(#pf1a14e2ae9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p63156f34a4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p63156f34a4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -691,7 +691,7 @@ L 282.252101 87.755294 L 282.252101 69.12 L 258.806723 69.12 z -" clip-path="url(#p20ad9b6bc3)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> +" clip-path="url(#pc5ffc28e1a)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> @@ -776,12 +776,12 @@ L 280.37701 80.673901 L 280.646807 80.668875 L 280.916605 80.665911 L 281.186402 80.664939 -" clip-path="url(#p20ad9b6bc3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc5ffc28e1a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc5ffc28e1a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -799,7 +799,7 @@ L 310.386555 87.755294 L 310.386555 69.12 L 286.941176 69.12 z -" clip-path="url(#p7bf0efe874)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> +" clip-path="url(#p10ffe396ce)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> @@ -884,12 +884,12 @@ L 308.511464 80.678772 L 308.781261 80.671014 L 309.051058 80.666439 L 309.320856 80.664939 -" clip-path="url(#p7bf0efe874)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10ffe396ce)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10ffe396ce)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -907,7 +907,7 @@ L 338.521008 87.755294 L 338.521008 69.12 L 315.07563 69.12 z -" clip-path="url(#p4a05afa31a)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> +" clip-path="url(#p6fc099c423)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> @@ -992,12 +992,12 @@ L 336.645918 80.677684 L 336.915715 80.670536 L 337.185512 80.666321 L 337.455309 80.664939 -" clip-path="url(#p4a05afa31a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6fc099c423)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6fc099c423)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1015,7 +1015,7 @@ L 366.655462 87.755294 L 366.655462 69.12 L 343.210084 69.12 z -" clip-path="url(#pca51826308)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> +" clip-path="url(#p8f67974980)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> @@ -1100,12 +1100,12 @@ L 364.780372 80.667048 L 365.050169 80.665865 L 365.319966 80.665167 L 365.589763 80.664939 -" clip-path="url(#pca51826308)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8f67974980)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8f67974980)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1123,7 +1123,7 @@ L 394.789916 87.755294 L 394.789916 69.12 L 371.344538 69.12 z -" clip-path="url(#p794d4764b2)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> +" clip-path="url(#p3e50034b52)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> @@ -1208,12 +1208,12 @@ L 392.914825 80.672311 L 393.184623 80.668177 L 393.45442 80.665738 L 393.724217 80.664939 -" clip-path="url(#p794d4764b2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3e50034b52)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3e50034b52)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1231,7 +1231,7 @@ L 422.92437 87.755294 L 422.92437 69.12 L 399.478992 69.12 z -" clip-path="url(#pa073a3b597)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> +" clip-path="url(#p44573d5222)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> @@ -1316,12 +1316,12 @@ L 421.049279 80.65606 L 421.319076 80.661039 L 421.588874 80.663975 L 421.858671 80.664939 -" clip-path="url(#pa073a3b597)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p44573d5222)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p44573d5222)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1339,7 +1339,7 @@ L 451.058824 87.755294 L 451.058824 69.12 L 427.613445 69.12 z -" clip-path="url(#p9a35640618)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> +" clip-path="url(#p8f0342cf01)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> @@ -1424,12 +1424,12 @@ L 449.183733 80.676724 L 449.45353 80.670115 L 449.723327 80.666217 L 449.993125 80.664939 -" clip-path="url(#p9a35640618)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8f0342cf01)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8f0342cf01)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1447,7 +1447,7 @@ L 479.193277 87.755294 L 479.193277 69.12 L 455.747899 69.12 z -" clip-path="url(#pa7f112e495)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> +" clip-path="url(#pb74ec38913)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> @@ -1532,12 +1532,12 @@ L 477.318187 80.667773 L 477.587984 80.666183 L 477.857781 80.665246 L 478.127578 80.664939 -" clip-path="url(#pa7f112e495)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb74ec38913)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb74ec38913)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1555,7 +1555,7 @@ L 507.327731 87.755294 L 507.327731 69.12 L 483.882353 69.12 z -" clip-path="url(#p2d1cef8fe0)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> +" clip-path="url(#p8dbaace941)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> @@ -1640,12 +1640,12 @@ L 505.45264 80.664428 L 505.722438 80.664714 L 505.992235 80.664883 L 506.262032 80.664939 -" clip-path="url(#p2d1cef8fe0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8dbaace941)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8dbaace941)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1663,7 +1663,7 @@ L 535.462185 87.755294 L 535.462185 69.12 L 512.016807 69.12 z -" clip-path="url(#p36e39e5105)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> +" clip-path="url(#pa2682b703d)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> @@ -1748,12 +1748,12 @@ L 533.587094 80.672024 L 533.856891 80.66805 L 534.126689 80.665707 L 534.396486 80.664939 -" clip-path="url(#p36e39e5105)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa2682b703d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa2682b703d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1771,7 +1771,7 @@ L 563.596639 87.755294 L 563.596639 69.12 L 540.151261 69.12 z -" clip-path="url(#p8f55ced3a9)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> +" clip-path="url(#pea9b6bf18c)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> @@ -1856,12 +1856,12 @@ L 561.721548 80.665934 L 561.991345 80.665376 L 562.261142 80.665047 L 562.53094 80.664939 -" clip-path="url(#p8f55ced3a9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pea9b6bf18c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pea9b6bf18c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1879,7 +1879,7 @@ L 591.731092 87.755294 L 591.731092 69.12 L 568.285714 69.12 z -" clip-path="url(#p9e33673930)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> +" clip-path="url(#pe822f11109)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> @@ -1964,12 +1964,12 @@ L 589.856002 80.685519 L 590.125799 80.673978 L 590.395596 80.667171 L 590.665393 80.664939 -" clip-path="url(#p9e33673930)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe822f11109)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe822f11109)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1987,7 +1987,7 @@ L 619.865546 87.755294 L 619.865546 69.12 L 596.420168 69.12 z -" clip-path="url(#pc1ae83cf21)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#pff7d44b1d2)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -2072,12 +2072,12 @@ L 617.990456 80.670055 L 618.260253 80.667186 L 618.53005 80.665494 L 618.799847 80.664939 -" clip-path="url(#pc1ae83cf21)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pff7d44b1d2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pff7d44b1d2)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2095,7 +2095,7 @@ L 113.445378 110.117647 L 113.445378 91.482353 L 90 91.482353 z -" clip-path="url(#p771b2544ec)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> +" clip-path="url(#paa20ba2038)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> @@ -2180,12 +2180,12 @@ L 111.570287 102.767724 L 111.840085 102.769162 L 112.109882 102.77001 L 112.379679 102.770289 -" clip-path="url(#p771b2544ec)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa20ba2038)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa20ba2038)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2203,7 +2203,7 @@ L 141.579832 110.117647 L 141.579832 91.482353 L 118.134454 91.482353 z -" clip-path="url(#p983b359634)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#pcba12c8461)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -2288,12 +2288,12 @@ L 139.704741 102.758326 L 139.974538 102.765035 L 140.244336 102.768991 L 140.514133 102.770289 -" clip-path="url(#p983b359634)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcba12c8461)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcba12c8461)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2311,7 +2311,7 @@ L 169.714286 110.117647 L 169.714286 91.482353 L 146.268908 91.482353 z -" clip-path="url(#p161f5d4351)" style="fill: #ffbdbd; opacity: 0.5; stroke: #ffbdbd; stroke-linejoin: miter"/> +" clip-path="url(#p0581f5f723)" style="fill: #ffbdbd; opacity: 0.5; stroke: #ffbdbd; stroke-linejoin: miter"/> @@ -2396,12 +2396,12 @@ L 167.839195 102.771472 L 168.108992 102.770809 L 168.378789 102.770417 L 168.648587 102.770289 -" clip-path="url(#p161f5d4351)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0581f5f723)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0581f5f723)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2419,7 +2419,7 @@ L 197.848739 110.117647 L 197.848739 91.482353 L 174.403361 91.482353 z -" clip-path="url(#p3dc254e16f)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> +" clip-path="url(#p4f967e9e71)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> @@ -2504,12 +2504,12 @@ L 195.973649 102.765973 L 196.243446 102.768393 L 196.513243 102.769821 L 196.78304 102.770289 -" clip-path="url(#p3dc254e16f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4f967e9e71)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4f967e9e71)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2527,7 +2527,7 @@ L 225.983193 110.117647 L 225.983193 91.482353 L 202.537815 91.482353 z -" clip-path="url(#pf6191326e1)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> +" clip-path="url(#p47a659cec8)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> @@ -2612,12 +2612,12 @@ L 224.108103 102.773462 L 224.3779 102.771683 L 224.647697 102.770633 L 224.917494 102.770289 -" clip-path="url(#pf6191326e1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p47a659cec8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p47a659cec8)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2635,7 +2635,7 @@ L 254.117647 110.117647 L 254.117647 91.482353 L 230.672269 91.482353 z -" clip-path="url(#pbf31bda7a5)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> +" clip-path="url(#p155df5e32e)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> @@ -2720,12 +2720,12 @@ L 252.242556 102.778909 L 252.512354 102.774075 L 252.782151 102.771224 L 253.051948 102.770289 -" clip-path="url(#pbf31bda7a5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p155df5e32e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p155df5e32e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2743,7 +2743,7 @@ L 282.252101 110.117647 L 282.252101 91.482353 L 258.806723 91.482353 z -" clip-path="url(#pedc7ff7cb3)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#pa12c83360d)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -2828,12 +2828,12 @@ L 280.37701 102.770016 L 280.646807 102.770169 L 280.916605 102.770259 L 281.186402 102.770289 -" clip-path="url(#pedc7ff7cb3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa12c83360d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa12c83360d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2851,7 +2851,7 @@ L 310.386555 110.117647 L 310.386555 91.482353 L 286.941176 91.482353 z -" clip-path="url(#pc75f9d3acd)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#pc6ae6bab4b)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -2936,12 +2936,12 @@ L 308.511464 102.773679 L 308.781261 102.771778 L 309.051058 102.770657 L 309.320856 102.770289 -" clip-path="url(#pc75f9d3acd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc6ae6bab4b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc6ae6bab4b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2959,7 +2959,7 @@ L 338.521008 110.117647 L 338.521008 91.482353 L 315.07563 91.482353 z -" clip-path="url(#paa8634621f)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> +" clip-path="url(#p9ee13aa270)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> @@ -3044,12 +3044,12 @@ L 336.645918 102.768967 L 336.915715 102.769708 L 337.185512 102.770145 L 337.455309 102.770289 -" clip-path="url(#paa8634621f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9ee13aa270)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9ee13aa270)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3067,7 +3067,7 @@ L 366.655462 110.117647 L 366.655462 91.482353 L 343.210084 91.482353 z -" clip-path="url(#p27502004ad)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#p0b4afa0955)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -3152,12 +3152,12 @@ L 364.780372 102.764435 L 365.050169 102.767718 L 365.319966 102.769654 L 365.589763 102.770289 -" clip-path="url(#p27502004ad)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0b4afa0955)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0b4afa0955)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3175,7 +3175,7 @@ L 394.789916 110.117647 L 394.789916 91.482353 L 371.344538 91.482353 z -" clip-path="url(#pb9cd48f2af)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#pa5f043a5e6)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -3260,12 +3260,12 @@ L 392.914825 102.766145 L 393.184623 102.768469 L 393.45442 102.769839 L 393.724217 102.770289 -" clip-path="url(#pb9cd48f2af)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa5f043a5e6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa5f043a5e6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3283,7 +3283,7 @@ L 422.92437 110.117647 L 422.92437 91.482353 L 399.478992 91.482353 z -" clip-path="url(#p83448004ed)" style="fill: #ffb1b1; opacity: 0.5; stroke: #ffb1b1; stroke-linejoin: miter"/> +" clip-path="url(#p6e8d73e255)" style="fill: #ffb1b1; opacity: 0.5; stroke: #ffb1b1; stroke-linejoin: miter"/> @@ -3368,12 +3368,12 @@ L 421.049279 102.771276 L 421.319076 102.770722 L 421.588874 102.770396 L 421.858671 102.770289 -" clip-path="url(#p83448004ed)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6e8d73e255)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6e8d73e255)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3391,7 +3391,7 @@ L 451.058824 110.117647 L 451.058824 91.482353 L 427.613445 91.482353 z -" clip-path="url(#pa7310d4fef)" style="fill: #8585ff; opacity: 0.5; stroke: #8585ff; stroke-linejoin: miter"/> +" clip-path="url(#pe534c56b31)" style="fill: #8585ff; opacity: 0.5; stroke: #8585ff; stroke-linejoin: miter"/> @@ -3476,12 +3476,12 @@ L 449.183733 102.785121 L 449.45353 102.776803 L 449.723327 102.771898 L 449.993125 102.770289 -" clip-path="url(#pa7310d4fef)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe534c56b31)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe534c56b31)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3499,7 +3499,7 @@ L 479.193277 110.117647 L 479.193277 91.482353 L 455.747899 91.482353 z -" clip-path="url(#pa3ff6dd05d)" style="fill: #ffbdbd; opacity: 0.5; stroke: #ffbdbd; stroke-linejoin: miter"/> +" clip-path="url(#p79f1ffd4a1)" style="fill: #ffbdbd; opacity: 0.5; stroke: #ffbdbd; stroke-linejoin: miter"/> @@ -3584,12 +3584,12 @@ L 477.318187 102.761584 L 477.587984 102.766466 L 477.857781 102.769344 L 478.127578 102.770289 -" clip-path="url(#pa3ff6dd05d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p79f1ffd4a1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p79f1ffd4a1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3607,7 +3607,7 @@ L 507.327731 110.117647 L 507.327731 91.482353 L 483.882353 91.482353 z -" clip-path="url(#pdd7dbfc6e5)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#p749537adc3)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -3692,12 +3692,12 @@ L 505.45264 102.779033 L 505.722438 102.774129 L 505.992235 102.771237 L 506.262032 102.770289 -" clip-path="url(#pdd7dbfc6e5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p749537adc3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p749537adc3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3715,7 +3715,7 @@ L 535.462185 110.117647 L 535.462185 91.482353 L 512.016807 91.482353 z -" clip-path="url(#p7d7308a247)" style="fill: #ffc5c5; opacity: 0.5; stroke: #ffc5c5; stroke-linejoin: miter"/> +" clip-path="url(#p971e814e84)" style="fill: #ffc5c5; opacity: 0.5; stroke: #ffc5c5; stroke-linejoin: miter"/> @@ -3800,12 +3800,12 @@ L 533.587094 102.762505 L 533.856891 102.76687 L 534.126689 102.769444 L 534.396486 102.770289 -" clip-path="url(#p7d7308a247)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p971e814e84)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p971e814e84)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3823,7 +3823,7 @@ L 563.596639 110.117647 L 563.596639 91.482353 L 540.151261 91.482353 z -" clip-path="url(#p17f45fdc95)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> +" clip-path="url(#p6b5c54924d)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> @@ -3908,12 +3908,12 @@ L 561.721548 102.773989 L 561.991345 102.771914 L 562.261142 102.77069 L 562.53094 102.770289 -" clip-path="url(#p17f45fdc95)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6b5c54924d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6b5c54924d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3931,7 +3931,7 @@ L 591.731092 110.117647 L 591.731092 91.482353 L 568.285714 91.482353 z -" clip-path="url(#p3174a88e12)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> +" clip-path="url(#p443daa1a85)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> @@ -4016,12 +4016,12 @@ L 589.856002 102.786793 L 590.125799 102.777538 L 590.395596 102.772079 L 590.665393 102.770289 -" clip-path="url(#p3174a88e12)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p443daa1a85)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p443daa1a85)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4039,7 +4039,7 @@ L 619.865546 110.117647 L 619.865546 91.482353 L 596.420168 91.482353 z -" clip-path="url(#p117dce5cb1)" style="fill: #adadff; opacity: 0.5; stroke: #adadff; stroke-linejoin: miter"/> +" clip-path="url(#p71fdfe8818)" style="fill: #adadff; opacity: 0.5; stroke: #adadff; stroke-linejoin: miter"/> @@ -4124,12 +4124,12 @@ L 617.990456 102.780009 L 618.260253 102.774558 L 618.53005 102.771343 L 618.799847 102.770289 -" clip-path="url(#p117dce5cb1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p71fdfe8818)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p71fdfe8818)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4147,7 +4147,7 @@ L 113.445378 132.48 L 113.445378 113.844706 L 90 113.844706 z -" clip-path="url(#p396af9a926)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> +" clip-path="url(#p9f66a72a57)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> @@ -4232,12 +4232,12 @@ L 111.570287 125.513942 L 111.840085 125.514648 L 112.109882 125.515065 L 112.379679 125.515202 -" clip-path="url(#p396af9a926)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9f66a72a57)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9f66a72a57)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4255,7 +4255,7 @@ L 141.579832 132.48 L 141.579832 113.844706 L 118.134454 113.844706 z -" clip-path="url(#p62c426d005)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> +" clip-path="url(#p1fc8352651)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> @@ -4340,12 +4340,12 @@ L 139.704741 125.520056 L 139.974538 125.517334 L 140.244336 125.515728 L 140.514133 125.515202 -" clip-path="url(#p62c426d005)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1fc8352651)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1fc8352651)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4363,7 +4363,7 @@ L 169.714286 132.48 L 169.714286 113.844706 L 146.268908 113.844706 z -" clip-path="url(#pb7b078aca4)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p1ef4124dce)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -4448,12 +4448,12 @@ L 167.839195 125.514499 L 168.108992 125.514893 L 168.378789 125.515125 L 168.648587 125.515202 -" clip-path="url(#pb7b078aca4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1ef4124dce)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1ef4124dce)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4471,7 +4471,7 @@ L 197.848739 132.48 L 197.848739 113.844706 L 174.403361 113.844706 z -" clip-path="url(#pe42403947e)" style="fill: #fffdfd; opacity: 0.5; stroke: #fffdfd; stroke-linejoin: miter"/> +" clip-path="url(#pc3d2c2d86d)" style="fill: #fffdfd; opacity: 0.5; stroke: #fffdfd; stroke-linejoin: miter"/> @@ -4556,12 +4556,12 @@ L 195.973649 125.522113 L 196.243446 125.518237 L 196.513243 125.515951 L 196.78304 125.515202 -" clip-path="url(#pe42403947e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc3d2c2d86d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc3d2c2d86d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4579,7 +4579,7 @@ L 225.983193 132.48 L 225.983193 113.844706 L 202.537815 113.844706 z -" clip-path="url(#pda6a691e25)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> +" clip-path="url(#pbbc43a80cc)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> @@ -4664,12 +4664,12 @@ L 224.108103 125.512703 L 224.3779 125.514104 L 224.647697 125.514931 L 224.917494 125.515202 -" clip-path="url(#pda6a691e25)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbbc43a80cc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbbc43a80cc)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4687,7 +4687,7 @@ L 254.117647 132.48 L 254.117647 113.844706 L 230.672269 113.844706 z -" clip-path="url(#p723cb98ac7)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> +" clip-path="url(#peb7f1b6323)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> @@ -4772,12 +4772,12 @@ L 252.242556 125.524869 L 252.512354 125.519447 L 252.782151 125.51625 L 253.051948 125.515202 -" clip-path="url(#p723cb98ac7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#peb7f1b6323)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#peb7f1b6323)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4795,7 +4795,7 @@ L 282.252101 132.48 L 282.252101 113.844706 L 258.806723 113.844706 z -" clip-path="url(#p69fda57e48)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> +" clip-path="url(#p7767b7b15c)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> @@ -4880,12 +4880,12 @@ L 280.37701 125.520904 L 280.646807 125.517706 L 280.916605 125.51582 L 281.186402 125.515202 -" clip-path="url(#p69fda57e48)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7767b7b15c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7767b7b15c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4903,7 +4903,7 @@ L 310.386555 132.48 L 310.386555 113.844706 L 286.941176 113.844706 z -" clip-path="url(#p71f97741af)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> +" clip-path="url(#pcec7450c06)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> @@ -4988,12 +4988,12 @@ L 308.511464 125.516419 L 308.781261 125.515736 L 309.051058 125.515334 L 309.320856 125.515202 -" clip-path="url(#p71f97741af)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcec7450c06)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcec7450c06)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5011,7 +5011,7 @@ L 338.521008 132.48 L 338.521008 113.844706 L 315.07563 113.844706 z -" clip-path="url(#pfd7400e714)" style="fill: #9595ff; opacity: 0.5; stroke: #9595ff; stroke-linejoin: miter"/> +" clip-path="url(#pd128c0de9b)" style="fill: #9595ff; opacity: 0.5; stroke: #9595ff; stroke-linejoin: miter"/> @@ -5096,12 +5096,12 @@ L 336.645918 125.518916 L 336.915715 125.516833 L 337.185512 125.515604 L 337.455309 125.515202 -" clip-path="url(#pfd7400e714)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd128c0de9b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd128c0de9b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5119,7 +5119,7 @@ L 366.655462 132.48 L 366.655462 113.844706 L 343.210084 113.844706 z -" clip-path="url(#p523a1d4c11)" style="fill: #5959ff; opacity: 0.5; stroke: #5959ff; stroke-linejoin: miter"/> +" clip-path="url(#p025b0c80e1)" style="fill: #5959ff; opacity: 0.5; stroke: #5959ff; stroke-linejoin: miter"/> @@ -5204,12 +5204,12 @@ L 364.780372 125.522911 L 365.050169 125.518588 L 365.319966 125.516038 L 365.589763 125.515202 -" clip-path="url(#p523a1d4c11)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p025b0c80e1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p025b0c80e1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5227,7 +5227,7 @@ L 394.789916 132.48 L 394.789916 113.844706 L 371.344538 113.844706 z -" clip-path="url(#p4c9c479ff2)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> +" clip-path="url(#p483f0e33b9)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> @@ -5312,12 +5312,12 @@ L 392.914825 125.515675 L 393.184623 125.515409 L 393.45442 125.515253 L 393.724217 125.515202 -" clip-path="url(#p4c9c479ff2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p483f0e33b9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p483f0e33b9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5335,7 +5335,7 @@ L 422.92437 132.48 L 422.92437 113.844706 L 399.478992 113.844706 z -" clip-path="url(#pcbb0ae4f4f)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> +" clip-path="url(#pdc246cce6d)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> @@ -5420,12 +5420,12 @@ L 421.049279 125.509866 L 421.319076 125.512858 L 421.588874 125.514623 L 421.858671 125.515202 -" clip-path="url(#pcbb0ae4f4f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdc246cce6d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdc246cce6d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5443,7 +5443,7 @@ L 451.058824 132.48 L 451.058824 113.844706 L 427.613445 113.844706 z -" clip-path="url(#pd6cc85824d)" style="fill: #3535ff; opacity: 0.5; stroke: #3535ff; stroke-linejoin: miter"/> +" clip-path="url(#p8ab5748e59)" style="fill: #3535ff; opacity: 0.5; stroke: #3535ff; stroke-linejoin: miter"/> @@ -5528,12 +5528,12 @@ L 449.183733 125.529886 L 449.45353 125.521651 L 449.723327 125.516795 L 449.993125 125.515202 -" clip-path="url(#pd6cc85824d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ab5748e59)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ab5748e59)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5551,7 +5551,7 @@ L 479.193277 132.48 L 479.193277 113.844706 L 455.747899 113.844706 z -" clip-path="url(#pe603d091bb)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> +" clip-path="url(#peca0aff093)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> @@ -5636,12 +5636,12 @@ L 477.318187 125.518861 L 477.587984 125.516809 L 477.857781 125.515598 L 478.127578 125.515202 -" clip-path="url(#pe603d091bb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#peca0aff093)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#peca0aff093)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5659,7 +5659,7 @@ L 507.327731 132.48 L 507.327731 113.844706 L 483.882353 113.844706 z -" clip-path="url(#pb7dccfee62)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> +" clip-path="url(#p95f2cc2d69)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> @@ -5744,12 +5744,12 @@ L 505.45264 125.51748 L 505.722438 125.516202 L 505.992235 125.515449 L 506.262032 125.515202 -" clip-path="url(#pb7dccfee62)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p95f2cc2d69)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p95f2cc2d69)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5767,7 +5767,7 @@ L 535.462185 132.48 L 535.462185 113.844706 L 512.016807 113.844706 z -" clip-path="url(#p356765db2f)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> +" clip-path="url(#pe68e197ce6)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> @@ -5852,12 +5852,12 @@ L 533.587094 125.511616 L 533.856891 125.513627 L 534.126689 125.514813 L 534.396486 125.515202 -" clip-path="url(#p356765db2f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe68e197ce6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe68e197ce6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5875,7 +5875,7 @@ L 563.596639 132.48 L 563.596639 113.844706 L 540.151261 113.844706 z -" clip-path="url(#p0e30ae344f)" style="fill: #ddddff; opacity: 0.5; stroke: #ddddff; stroke-linejoin: miter"/> +" clip-path="url(#pda78186180)" style="fill: #ddddff; opacity: 0.5; stroke: #ddddff; stroke-linejoin: miter"/> @@ -5960,12 +5960,12 @@ L 561.721548 125.511292 L 561.991345 125.513484 L 562.261142 125.514777 L 562.53094 125.515202 -" clip-path="url(#p0e30ae344f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pda78186180)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pda78186180)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5983,7 +5983,7 @@ L 591.731092 132.48 L 591.731092 113.844706 L 568.285714 113.844706 z -" clip-path="url(#pc403993c76)" style="fill: #3939ff; opacity: 0.5; stroke: #3939ff; stroke-linejoin: miter"/> +" clip-path="url(#peb5f14db36)" style="fill: #3939ff; opacity: 0.5; stroke: #3939ff; stroke-linejoin: miter"/> @@ -6068,12 +6068,12 @@ L 589.856002 125.532233 L 590.125799 125.522682 L 590.395596 125.517049 L 590.665393 125.515202 -" clip-path="url(#pc403993c76)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#peb5f14db36)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#peb5f14db36)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6091,7 +6091,7 @@ L 619.865546 132.48 L 619.865546 113.844706 L 596.420168 113.844706 z -" clip-path="url(#p23ec310a62)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> +" clip-path="url(#p671291ff40)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> @@ -6176,12 +6176,12 @@ L 617.990456 125.521835 L 618.260253 125.518115 L 618.53005 125.515921 L 618.799847 125.515202 -" clip-path="url(#p23ec310a62)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p671291ff40)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p671291ff40)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6199,7 +6199,7 @@ L 113.445378 154.842353 L 113.445378 136.207059 L 90 136.207059 z -" clip-path="url(#p6ec2047626)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> +" clip-path="url(#p868db90bdc)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> @@ -6284,12 +6284,12 @@ L 111.570287 145.333485 L 111.840085 145.339008 L 112.109882 145.342264 L 112.379679 145.343333 -" clip-path="url(#p6ec2047626)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p868db90bdc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p868db90bdc)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6307,7 +6307,7 @@ L 141.579832 154.842353 L 141.579832 136.207059 L 118.134454 136.207059 z -" clip-path="url(#pb718155157)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> +" clip-path="url(#pf3897ab9ac)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> @@ -6392,12 +6392,12 @@ L 139.704741 145.330453 L 139.974538 145.337676 L 140.244336 145.341935 L 140.514133 145.343333 -" clip-path="url(#pb718155157)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf3897ab9ac)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf3897ab9ac)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6415,7 +6415,7 @@ L 169.714286 154.842353 L 169.714286 136.207059 L 146.268908 136.207059 z -" clip-path="url(#p876fa67650)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> +" clip-path="url(#p2727725f25)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> @@ -6500,12 +6500,12 @@ L 167.839195 145.346775 L 168.108992 145.344845 L 168.378789 145.343706 L 168.648587 145.343333 -" clip-path="url(#p876fa67650)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2727725f25)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2727725f25)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6523,7 +6523,7 @@ L 197.848739 154.842353 L 197.848739 136.207059 L 174.403361 136.207059 z -" clip-path="url(#pbf19884b28)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#pa995662f1c)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -6608,12 +6608,12 @@ L 195.973649 145.325163 L 196.243446 145.335353 L 196.513243 145.341362 L 196.78304 145.343333 -" clip-path="url(#pbf19884b28)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa995662f1c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa995662f1c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6631,7 +6631,7 @@ L 225.983193 154.842353 L 225.983193 136.207059 L 202.537815 136.207059 z -" clip-path="url(#pdd9edce5ff)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> +" clip-path="url(#p5ef8c39a61)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> @@ -6716,12 +6716,12 @@ L 224.108103 145.336531 L 224.3779 145.340345 L 224.647697 145.342595 L 224.917494 145.343333 -" clip-path="url(#pdd9edce5ff)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5ef8c39a61)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5ef8c39a61)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6739,7 +6739,7 @@ L 254.117647 154.842353 L 254.117647 136.207059 L 230.672269 136.207059 z -" clip-path="url(#pda3ae34b11)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> +" clip-path="url(#pf234922f7e)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> @@ -6824,12 +6824,12 @@ L 252.242556 145.354306 L 252.512354 145.348152 L 252.782151 145.344523 L 253.051948 145.343333 -" clip-path="url(#pda3ae34b11)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf234922f7e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf234922f7e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6847,7 +6847,7 @@ L 282.252101 154.842353 L 282.252101 136.207059 L 258.806723 136.207059 z -" clip-path="url(#p79123b3679)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> +" clip-path="url(#p9c402b563d)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> @@ -6932,12 +6932,12 @@ L 280.37701 145.360615 L 280.646807 145.350923 L 280.916605 145.345207 L 281.186402 145.343333 -" clip-path="url(#p79123b3679)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9c402b563d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9c402b563d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6955,7 +6955,7 @@ L 310.386555 154.842353 L 310.386555 136.207059 L 286.941176 136.207059 z -" clip-path="url(#p0deaef4cc4)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> +" clip-path="url(#p10d7fd63f4)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> @@ -7040,12 +7040,12 @@ L 308.511464 145.358301 L 308.781261 145.349907 L 309.051058 145.344956 L 309.320856 145.343333 -" clip-path="url(#p0deaef4cc4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10d7fd63f4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10d7fd63f4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7063,7 +7063,7 @@ L 338.521008 154.842353 L 338.521008 136.207059 L 315.07563 136.207059 z -" clip-path="url(#p24e249078d)" style="fill: #5555ff; opacity: 0.5; stroke: #5555ff; stroke-linejoin: miter"/> +" clip-path="url(#pe14aaf34f5)" style="fill: #5555ff; opacity: 0.5; stroke: #5555ff; stroke-linejoin: miter"/> @@ -7148,12 +7148,12 @@ L 336.645918 145.368196 L 336.915715 145.354253 L 337.185512 145.34603 L 337.455309 145.343333 -" clip-path="url(#p24e249078d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe14aaf34f5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe14aaf34f5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7171,7 +7171,7 @@ L 366.655462 154.842353 L 366.655462 136.207059 L 343.210084 136.207059 z -" clip-path="url(#pf4c50f592b)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> +" clip-path="url(#p7283f5ac9a)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> @@ -7256,12 +7256,12 @@ L 364.780372 145.3529 L 365.050169 145.347535 L 365.319966 145.34437 L 365.589763 145.343333 -" clip-path="url(#pf4c50f592b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7283f5ac9a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7283f5ac9a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7279,7 +7279,7 @@ L 394.789916 154.842353 L 394.789916 136.207059 L 371.344538 136.207059 z -" clip-path="url(#p1457a0ab8b)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#p6957460ff0)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -7364,12 +7364,12 @@ L 392.914825 145.348299 L 393.184623 145.345514 L 393.45442 145.343871 L 393.724217 145.343333 -" clip-path="url(#p1457a0ab8b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6957460ff0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6957460ff0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7387,7 +7387,7 @@ L 422.92437 154.842353 L 422.92437 136.207059 L 399.478992 136.207059 z -" clip-path="url(#p39c902ec83)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> +" clip-path="url(#p52fedb8d00)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> @@ -7472,12 +7472,12 @@ L 421.049279 145.344643 L 421.319076 145.343908 L 421.588874 145.343475 L 421.858671 145.343333 -" clip-path="url(#p39c902ec83)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p52fedb8d00)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p52fedb8d00)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7495,7 +7495,7 @@ L 451.058824 154.842353 L 451.058824 136.207059 L 427.613445 136.207059 z -" clip-path="url(#pd103ff0fb6)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> +" clip-path="url(#p32d623d05c)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> @@ -7580,12 +7580,12 @@ L 449.183733 145.348759 L 449.45353 145.345716 L 449.723327 145.343921 L 449.993125 145.343333 -" clip-path="url(#pd103ff0fb6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p32d623d05c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p32d623d05c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7603,7 +7603,7 @@ L 479.193277 154.842353 L 479.193277 136.207059 L 455.747899 136.207059 z -" clip-path="url(#pac9e5f1447)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> +" clip-path="url(#p1d03ff7a72)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> @@ -7688,12 +7688,12 @@ L 477.318187 145.332951 L 477.587984 145.338773 L 477.857781 145.342206 L 478.127578 145.343333 -" clip-path="url(#pac9e5f1447)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1d03ff7a72)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1d03ff7a72)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7711,7 +7711,7 @@ L 507.327731 154.842353 L 507.327731 136.207059 L 483.882353 136.207059 z -" clip-path="url(#p456cca710a)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#p65704286df)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -7796,12 +7796,12 @@ L 505.45264 145.344208 L 505.722438 145.343717 L 505.992235 145.343428 L 506.262032 145.343333 -" clip-path="url(#p456cca710a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p65704286df)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p65704286df)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7819,7 +7819,7 @@ L 535.462185 154.842353 L 535.462185 136.207059 L 512.016807 136.207059 z -" clip-path="url(#pca46722ea9)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#pda4a128a94)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -7904,12 +7904,12 @@ L 533.587094 145.342733 L 533.856891 145.343069 L 534.126689 145.343268 L 534.396486 145.343333 -" clip-path="url(#pca46722ea9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pda4a128a94)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pda4a128a94)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7927,7 +7927,7 @@ L 563.596639 154.842353 L 563.596639 136.207059 L 540.151261 136.207059 z -" clip-path="url(#p942f507cac)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> +" clip-path="url(#pba6fd0a718)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> @@ -8012,12 +8012,12 @@ L 561.721548 145.353708 L 561.991345 145.347889 L 562.261142 145.344458 L 562.53094 145.343333 -" clip-path="url(#p942f507cac)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pba6fd0a718)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pba6fd0a718)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8035,7 +8035,7 @@ L 591.731092 154.842353 L 591.731092 136.207059 L 568.285714 136.207059 z -" clip-path="url(#pe6a1e5ed1a)" style="fill: #4141ff; opacity: 0.5; stroke: #4141ff; stroke-linejoin: miter"/> +" clip-path="url(#pf8c5535480)" style="fill: #4141ff; opacity: 0.5; stroke: #4141ff; stroke-linejoin: miter"/> @@ -8120,12 +8120,12 @@ L 589.856002 145.365246 L 590.125799 145.352957 L 590.395596 145.34571 L 590.665393 145.343333 -" clip-path="url(#pe6a1e5ed1a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf8c5535480)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf8c5535480)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8143,7 +8143,7 @@ L 619.865546 154.842353 L 619.865546 136.207059 L 596.420168 136.207059 z -" clip-path="url(#pdf7f34e548)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> +" clip-path="url(#p52e7370a09)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> @@ -8228,12 +8228,12 @@ L 617.990456 145.350949 L 618.260253 145.346678 L 618.53005 145.344159 L 618.799847 145.343333 -" clip-path="url(#pdf7f34e548)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p52e7370a09)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p52e7370a09)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8251,7 +8251,7 @@ L 113.445378 177.204706 L 113.445378 158.569412 L 90 158.569412 z -" clip-path="url(#p267278100e)" style="fill: #ffd1d1; opacity: 0.5; stroke: #ffd1d1; stroke-linejoin: miter"/> +" clip-path="url(#p7b7d9c8861)" style="fill: #ffd1d1; opacity: 0.5; stroke: #ffd1d1; stroke-linejoin: miter"/> @@ -8336,12 +8336,12 @@ L 111.570287 167.339939 L 111.840085 167.339927 L 112.109882 167.33992 L 112.379679 167.339918 -" clip-path="url(#p267278100e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7b7d9c8861)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7b7d9c8861)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8359,7 +8359,7 @@ L 141.579832 177.204706 L 141.579832 158.569412 L 118.134454 158.569412 z -" clip-path="url(#p65a882025c)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> +" clip-path="url(#pa869698614)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> @@ -8444,12 +8444,12 @@ L 139.704741 167.340277 L 139.974538 167.340076 L 140.244336 167.339957 L 140.514133 167.339918 -" clip-path="url(#p65a882025c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa869698614)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa869698614)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8467,7 +8467,7 @@ L 169.714286 177.204706 L 169.714286 158.569412 L 146.268908 158.569412 z -" clip-path="url(#p3f9b3c24d5)" style="fill: #ffb1b1; opacity: 0.5; stroke: #ffb1b1; stroke-linejoin: miter"/> +" clip-path="url(#p0056026b13)" style="fill: #ffb1b1; opacity: 0.5; stroke: #ffb1b1; stroke-linejoin: miter"/> @@ -8552,12 +8552,12 @@ L 167.839195 167.34262 L 168.108992 167.341105 L 168.378789 167.340211 L 168.648587 167.339918 -" clip-path="url(#p3f9b3c24d5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0056026b13)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0056026b13)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8575,7 +8575,7 @@ L 197.848739 177.204706 L 197.848739 158.569412 L 174.403361 158.569412 z -" clip-path="url(#p776a731e53)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> +" clip-path="url(#p6779ca5cc4)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> @@ -8660,12 +8660,12 @@ L 195.973649 167.332598 L 196.243446 167.336703 L 196.513243 167.339124 L 196.78304 167.339918 -" clip-path="url(#p776a731e53)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6779ca5cc4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6779ca5cc4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8683,7 +8683,7 @@ L 225.983193 177.204706 L 225.983193 158.569412 L 202.537815 158.569412 z -" clip-path="url(#pf836ac79a9)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p6256e9eb02)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -8768,12 +8768,12 @@ L 224.108103 167.332915 L 224.3779 167.336842 L 224.647697 167.339158 L 224.917494 167.339918 -" clip-path="url(#pf836ac79a9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6256e9eb02)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6256e9eb02)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8791,7 +8791,7 @@ L 254.117647 177.204706 L 254.117647 158.569412 L 230.672269 158.569412 z -" clip-path="url(#p6b356cddf0)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> +" clip-path="url(#p63e0742f41)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> @@ -8876,12 +8876,12 @@ L 252.242556 167.340242 L 252.512354 167.34006 L 252.782151 167.339953 L 253.051948 167.339918 -" clip-path="url(#p6b356cddf0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p63e0742f41)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p63e0742f41)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8899,7 +8899,7 @@ L 282.252101 177.204706 L 282.252101 158.569412 L 258.806723 158.569412 z -" clip-path="url(#peadbaa45d5)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> +" clip-path="url(#p810e2e80b0)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> @@ -8984,12 +8984,12 @@ L 280.37701 167.338628 L 280.646807 167.339351 L 280.916605 167.339778 L 281.186402 167.339918 -" clip-path="url(#peadbaa45d5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p810e2e80b0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p810e2e80b0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9007,7 +9007,7 @@ L 310.386555 177.204706 L 310.386555 158.569412 L 286.941176 158.569412 z -" clip-path="url(#p1d8ef33746)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> +" clip-path="url(#p21a2fa0dc5)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> @@ -9092,12 +9092,12 @@ L 308.511464 167.335093 L 308.781261 167.337799 L 309.051058 167.339395 L 309.320856 167.339918 -" clip-path="url(#p1d8ef33746)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p21a2fa0dc5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p21a2fa0dc5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9115,7 +9115,7 @@ L 338.521008 177.204706 L 338.521008 158.569412 L 315.07563 158.569412 z -" clip-path="url(#p19dde373a8)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> +" clip-path="url(#p38a94023d5)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> @@ -9200,12 +9200,12 @@ L 336.645918 167.343142 L 336.915715 167.341334 L 337.185512 167.340268 L 337.455309 167.339918 -" clip-path="url(#p19dde373a8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p38a94023d5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p38a94023d5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9223,7 +9223,7 @@ L 366.655462 177.204706 L 366.655462 158.569412 L 343.210084 158.569412 z -" clip-path="url(#p210c357719)" style="fill: #6565ff; opacity: 0.5; stroke: #6565ff; stroke-linejoin: miter"/> +" clip-path="url(#p71f37b03da)" style="fill: #6565ff; opacity: 0.5; stroke: #6565ff; stroke-linejoin: miter"/> @@ -9308,12 +9308,12 @@ L 364.780372 167.349718 L 365.050169 167.344222 L 365.319966 167.340981 L 365.589763 167.339918 -" clip-path="url(#p210c357719)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p71f37b03da)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p71f37b03da)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9331,7 +9331,7 @@ L 394.789916 177.204706 L 394.789916 158.569412 L 371.344538 158.569412 z -" clip-path="url(#p94a2401e6c)" style="fill: #a9a9ff; opacity: 0.5; stroke: #a9a9ff; stroke-linejoin: miter"/> +" clip-path="url(#pd050fccd69)" style="fill: #a9a9ff; opacity: 0.5; stroke: #a9a9ff; stroke-linejoin: miter"/> @@ -9416,12 +9416,12 @@ L 392.914825 167.341655 L 393.184623 167.340681 L 393.45442 167.340106 L 393.724217 167.339918 -" clip-path="url(#p94a2401e6c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd050fccd69)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd050fccd69)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9439,7 +9439,7 @@ L 422.92437 177.204706 L 422.92437 158.569412 L 399.478992 158.569412 z -" clip-path="url(#p5fdf07659c)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> +" clip-path="url(#pef4b787fce)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> @@ -9524,12 +9524,12 @@ L 421.049279 167.354294 L 421.319076 167.346232 L 421.588874 167.341478 L 421.858671 167.339918 -" clip-path="url(#p5fdf07659c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pef4b787fce)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pef4b787fce)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9547,7 +9547,7 @@ L 451.058824 177.204706 L 451.058824 158.569412 L 427.613445 158.569412 z -" clip-path="url(#p875417ca2d)" style="fill: #0000f7; opacity: 0.5; stroke: #0000f7; stroke-linejoin: miter"/> +" clip-path="url(#pcfe518e987)" style="fill: #0000f7; opacity: 0.5; stroke: #0000f7; stroke-linejoin: miter"/> @@ -9632,12 +9632,12 @@ L 449.183733 167.3586 L 449.45353 167.348123 L 449.723327 167.341945 L 449.993125 167.339918 -" clip-path="url(#p875417ca2d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcfe518e987)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcfe518e987)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9655,7 +9655,7 @@ L 479.193277 177.204706 L 479.193277 158.569412 L 455.747899 158.569412 z -" clip-path="url(#pb0c60c9706)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> +" clip-path="url(#p93e68949c0)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> @@ -9740,12 +9740,12 @@ L 477.318187 167.349211 L 477.587984 167.344 L 477.857781 167.340926 L 478.127578 167.339918 -" clip-path="url(#pb0c60c9706)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p93e68949c0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p93e68949c0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9763,7 +9763,7 @@ L 507.327731 177.204706 L 507.327731 158.569412 L 483.882353 158.569412 z -" clip-path="url(#p39e4ac9b8e)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> +" clip-path="url(#p4e5ed61d79)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> @@ -9848,12 +9848,12 @@ L 505.45264 167.335842 L 505.722438 167.338128 L 505.992235 167.339476 L 506.262032 167.339918 -" clip-path="url(#p39e4ac9b8e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4e5ed61d79)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4e5ed61d79)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9871,7 +9871,7 @@ L 535.462185 177.204706 L 535.462185 158.569412 L 512.016807 158.569412 z -" clip-path="url(#p2cbccad164)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> +" clip-path="url(#pde6bd025d9)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> @@ -9956,12 +9956,12 @@ L 533.587094 167.340062 L 533.856891 167.339981 L 534.126689 167.339934 L 534.396486 167.339918 -" clip-path="url(#p2cbccad164)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pde6bd025d9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pde6bd025d9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9979,7 +9979,7 @@ L 563.596639 177.204706 L 563.596639 158.569412 L 540.151261 158.569412 z -" clip-path="url(#p63fc5f4630)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#pda3de97b74)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -10064,12 +10064,12 @@ L 561.721548 167.336189 L 561.991345 167.33828 L 562.261142 167.339513 L 562.53094 167.339918 -" clip-path="url(#p63fc5f4630)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pda3de97b74)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pda3de97b74)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10087,7 +10087,7 @@ L 591.731092 177.204706 L 591.731092 158.569412 L 568.285714 158.569412 z -" clip-path="url(#pcd5bd504dd)" style="fill: #1515ff; opacity: 0.5; stroke: #1515ff; stroke-linejoin: miter"/> +" clip-path="url(#pc786f0834a)" style="fill: #1515ff; opacity: 0.5; stroke: #1515ff; stroke-linejoin: miter"/> @@ -10172,12 +10172,12 @@ L 589.856002 167.355758 L 590.125799 167.346875 L 590.395596 167.341636 L 590.665393 167.339918 -" clip-path="url(#pcd5bd504dd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc786f0834a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc786f0834a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10195,7 +10195,7 @@ L 619.865546 177.204706 L 619.865546 158.569412 L 596.420168 158.569412 z -" clip-path="url(#p46cd8a3dc8)" style="fill: #6d6dff; opacity: 0.5; stroke: #6d6dff; stroke-linejoin: miter"/> +" clip-path="url(#pa3be117fbc)" style="fill: #6d6dff; opacity: 0.5; stroke: #6d6dff; stroke-linejoin: miter"/> @@ -10280,12 +10280,12 @@ L 617.990456 167.349142 L 618.260253 167.343969 L 618.53005 167.340919 L 618.799847 167.339918 -" clip-path="url(#p46cd8a3dc8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa3be117fbc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa3be117fbc)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10303,7 +10303,7 @@ L 113.445378 199.567059 L 113.445378 180.931765 L 90 180.931765 z -" clip-path="url(#pb61ab75cdb)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#p021cd82c03)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -10388,12 +10388,12 @@ L 111.570287 191.985482 L 111.840085 191.985884 L 112.109882 191.986121 L 112.379679 191.986199 -" clip-path="url(#pb61ab75cdb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p021cd82c03)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p021cd82c03)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10411,7 +10411,7 @@ L 141.579832 199.567059 L 141.579832 180.931765 L 118.134454 180.931765 z -" clip-path="url(#pf00ec9219d)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> +" clip-path="url(#pb875ceb842)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> @@ -10496,12 +10496,12 @@ L 139.704741 191.977935 L 139.974538 191.982569 L 140.244336 191.985303 L 140.514133 191.986199 -" clip-path="url(#pf00ec9219d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb875ceb842)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb875ceb842)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10519,7 +10519,7 @@ L 169.714286 199.567059 L 169.714286 180.931765 L 146.268908 180.931765 z -" clip-path="url(#p1f9612cdfb)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#pd1b6e02e0c)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -10604,12 +10604,12 @@ L 167.839195 191.995921 L 168.108992 191.990469 L 168.378789 191.987254 L 168.648587 191.986199 -" clip-path="url(#p1f9612cdfb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd1b6e02e0c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd1b6e02e0c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10627,7 +10627,7 @@ L 197.848739 199.567059 L 197.848739 180.931765 L 174.403361 180.931765 z -" clip-path="url(#p3261dafb30)" style="fill: #ffc9c9; opacity: 0.5; stroke: #ffc9c9; stroke-linejoin: miter"/> +" clip-path="url(#p7fa91a99a2)" style="fill: #ffc9c9; opacity: 0.5; stroke: #ffc9c9; stroke-linejoin: miter"/> @@ -10712,12 +10712,12 @@ L 195.973649 191.977862 L 196.243446 191.982537 L 196.513243 191.985295 L 196.78304 191.986199 -" clip-path="url(#p3261dafb30)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7fa91a99a2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7fa91a99a2)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10735,7 +10735,7 @@ L 225.983193 199.567059 L 225.983193 180.931765 L 202.537815 180.931765 z -" clip-path="url(#p20285ba1f5)" style="fill: #ffc5c5; opacity: 0.5; stroke: #ffc5c5; stroke-linejoin: miter"/> +" clip-path="url(#pf0d92b94b3)" style="fill: #ffc5c5; opacity: 0.5; stroke: #ffc5c5; stroke-linejoin: miter"/> @@ -10820,12 +10820,12 @@ L 224.108103 191.979412 L 224.3779 191.983218 L 224.647697 191.985463 L 224.917494 191.986199 -" clip-path="url(#p20285ba1f5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf0d92b94b3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf0d92b94b3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10843,7 +10843,7 @@ L 254.117647 199.567059 L 254.117647 180.931765 L 230.672269 180.931765 z -" clip-path="url(#p03fabaadb3)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p3d860f66bf)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -10928,12 +10928,12 @@ L 252.242556 191.965628 L 252.512354 191.977164 L 252.782151 191.983967 L 253.051948 191.986199 -" clip-path="url(#p03fabaadb3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3d860f66bf)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3d860f66bf)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10951,7 +10951,7 @@ L 282.252101 199.567059 L 282.252101 180.931765 L 258.806723 180.931765 z -" clip-path="url(#pfd2c13b89e)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> +" clip-path="url(#p8486e961a2)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> @@ -11036,12 +11036,12 @@ L 280.37701 191.987483 L 280.646807 191.986763 L 280.916605 191.986338 L 281.186402 191.986199 -" clip-path="url(#pfd2c13b89e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8486e961a2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8486e961a2)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11059,7 +11059,7 @@ L 310.386555 199.567059 L 310.386555 180.931765 L 286.941176 180.931765 z -" clip-path="url(#p4701b3e777)" style="fill: #ffc9c9; opacity: 0.5; stroke: #ffc9c9; stroke-linejoin: miter"/> +" clip-path="url(#p46e72157e5)" style="fill: #ffc9c9; opacity: 0.5; stroke: #ffc9c9; stroke-linejoin: miter"/> @@ -11144,12 +11144,12 @@ L 308.511464 191.979301 L 308.781261 191.983169 L 309.051058 191.985451 L 309.320856 191.986199 -" clip-path="url(#p4701b3e777)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p46e72157e5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p46e72157e5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11167,7 +11167,7 @@ L 338.521008 199.567059 L 338.521008 180.931765 L 315.07563 180.931765 z -" clip-path="url(#p53cc0487db)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> +" clip-path="url(#p15cfc4435c)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> @@ -11252,12 +11252,12 @@ L 336.645918 191.975553 L 336.915715 191.981523 L 337.185512 191.985044 L 337.455309 191.986199 -" clip-path="url(#p53cc0487db)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p15cfc4435c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p15cfc4435c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11275,7 +11275,7 @@ L 366.655462 199.567059 L 366.655462 180.931765 L 343.210084 180.931765 z -" clip-path="url(#p6a93a6f691)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> +" clip-path="url(#p1552cb7338)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> @@ -11360,12 +11360,12 @@ L 364.780372 191.98442 L 365.050169 191.985418 L 365.319966 191.986006 L 365.589763 191.986199 -" clip-path="url(#p6a93a6f691)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1552cb7338)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1552cb7338)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11383,7 +11383,7 @@ L 394.789916 199.567059 L 394.789916 180.931765 L 371.344538 180.931765 z -" clip-path="url(#pa74b053b34)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> +" clip-path="url(#p10959895b3)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> @@ -11468,12 +11468,12 @@ L 392.914825 191.985499 L 393.184623 191.985892 L 393.45442 191.986123 L 393.724217 191.986199 -" clip-path="url(#pa74b053b34)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10959895b3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10959895b3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11491,7 +11491,7 @@ L 422.92437 199.567059 L 422.92437 180.931765 L 399.478992 180.931765 z -" clip-path="url(#pdaa779840f)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#p78c178d802)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -11576,12 +11576,12 @@ L 421.049279 191.995518 L 421.319076 191.990292 L 421.588874 191.98721 L 421.858671 191.986199 -" clip-path="url(#pdaa779840f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p78c178d802)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p78c178d802)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11599,7 +11599,7 @@ L 451.058824 199.567059 L 451.058824 180.931765 L 427.613445 180.931765 z -" clip-path="url(#p521d8defc7)" style="fill: #8585ff; opacity: 0.5; stroke: #8585ff; stroke-linejoin: miter"/> +" clip-path="url(#pe58c915f9e)" style="fill: #8585ff; opacity: 0.5; stroke: #8585ff; stroke-linejoin: miter"/> @@ -11684,12 +11684,12 @@ L 449.183733 192.007995 L 449.45353 191.995772 L 449.723327 191.988564 L 449.993125 191.986199 -" clip-path="url(#p521d8defc7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe58c915f9e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe58c915f9e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11707,7 +11707,7 @@ L 479.193277 199.567059 L 479.193277 180.931765 L 455.747899 180.931765 z -" clip-path="url(#pe2769acf4a)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> +" clip-path="url(#pfd792c7f2e)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> @@ -11792,12 +11792,12 @@ L 477.318187 191.990027 L 477.587984 191.98788 L 477.857781 191.986614 L 478.127578 191.986199 -" clip-path="url(#pe2769acf4a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfd792c7f2e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfd792c7f2e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11815,7 +11815,7 @@ L 507.327731 199.567059 L 507.327731 180.931765 L 483.882353 180.931765 z -" clip-path="url(#p63828ac259)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> +" clip-path="url(#pb53ead9b93)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> @@ -11900,12 +11900,12 @@ L 505.45264 191.990307 L 505.722438 191.988003 L 505.992235 191.986645 L 506.262032 191.986199 -" clip-path="url(#p63828ac259)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb53ead9b93)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb53ead9b93)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11923,7 +11923,7 @@ L 535.462185 199.567059 L 535.462185 180.931765 L 512.016807 180.931765 z -" clip-path="url(#p7d56a040ac)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#p257a024e6d)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -12008,12 +12008,12 @@ L 533.587094 191.988366 L 533.856891 191.987151 L 534.126689 191.986434 L 534.396486 191.986199 -" clip-path="url(#p7d56a040ac)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p257a024e6d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p257a024e6d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12031,7 +12031,7 @@ L 563.596639 199.567059 L 563.596639 180.931765 L 540.151261 180.931765 z -" clip-path="url(#p24d3d9f639)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> +" clip-path="url(#p304937ca2e)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> @@ -12116,12 +12116,12 @@ L 561.721548 191.996121 L 561.991345 191.990557 L 562.261142 191.987275 L 562.53094 191.986199 -" clip-path="url(#p24d3d9f639)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p304937ca2e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p304937ca2e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12139,7 +12139,7 @@ L 591.731092 199.567059 L 591.731092 180.931765 L 568.285714 180.931765 z -" clip-path="url(#pd1db96e15c)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> +" clip-path="url(#p7b45e722a5)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> @@ -12224,12 +12224,12 @@ L 589.856002 192.003652 L 590.125799 191.993864 L 590.395596 191.988092 L 590.665393 191.986199 -" clip-path="url(#pd1db96e15c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7b45e722a5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7b45e722a5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12247,7 +12247,7 @@ L 619.865546 199.567059 L 619.865546 180.931765 L 596.420168 180.931765 z -" clip-path="url(#p0e2343328e)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#pa541e705a3)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -12332,12 +12332,12 @@ L 617.990456 191.994312 L 618.260253 191.989762 L 618.53005 191.987079 L 618.799847 191.986199 -" clip-path="url(#p0e2343328e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa541e705a3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa541e705a3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12355,7 +12355,7 @@ L 113.445378 221.929412 L 113.445378 203.294118 L 90 203.294118 z -" clip-path="url(#pd514b7df6a)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> +" clip-path="url(#p5b851a4b30)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> @@ -12440,12 +12440,12 @@ L 111.570287 213.456812 L 111.840085 213.453205 L 112.109882 213.451078 L 112.379679 213.45038 -" clip-path="url(#pd514b7df6a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5b851a4b30)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5b851a4b30)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12463,7 +12463,7 @@ L 141.579832 221.929412 L 141.579832 203.294118 L 118.134454 203.294118 z -" clip-path="url(#p760fa1d086)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> +" clip-path="url(#pe33e5ce46a)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> @@ -12548,12 +12548,12 @@ L 139.704741 213.464813 L 139.974538 213.456719 L 140.244336 213.451946 L 140.514133 213.45038 -" clip-path="url(#p760fa1d086)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe33e5ce46a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe33e5ce46a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12571,7 +12571,7 @@ L 169.714286 221.929412 L 169.714286 203.294118 L 146.268908 203.294118 z -" clip-path="url(#pee2dd52631)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> +" clip-path="url(#p65e0d95035)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> @@ -12656,12 +12656,12 @@ L 167.839195 213.468619 L 168.108992 213.458391 L 168.378789 213.452359 L 168.648587 213.45038 -" clip-path="url(#pee2dd52631)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p65e0d95035)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p65e0d95035)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12679,7 +12679,7 @@ L 197.848739 221.929412 L 197.848739 203.294118 L 174.403361 203.294118 z -" clip-path="url(#p3f26631896)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> +" clip-path="url(#p986e478f11)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> @@ -12764,12 +12764,12 @@ L 195.973649 213.454131 L 196.243446 213.452027 L 196.513243 213.450787 L 196.78304 213.45038 -" clip-path="url(#p3f26631896)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p986e478f11)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p986e478f11)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12787,7 +12787,7 @@ L 225.983193 221.929412 L 225.983193 203.294118 L 202.537815 203.294118 z -" clip-path="url(#p5d739f89b7)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> +" clip-path="url(#p8d7a1996a3)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> @@ -12872,12 +12872,12 @@ L 224.108103 213.434237 L 224.3779 213.44329 L 224.647697 213.448629 L 224.917494 213.45038 -" clip-path="url(#p5d739f89b7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8d7a1996a3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8d7a1996a3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12895,7 +12895,7 @@ L 254.117647 221.929412 L 254.117647 203.294118 L 230.672269 203.294118 z -" clip-path="url(#p3b25755717)" style="fill: #ff7979; opacity: 0.5; stroke: #ff7979; stroke-linejoin: miter"/> +" clip-path="url(#p657021d3ef)" style="fill: #ff7979; opacity: 0.5; stroke: #ff7979; stroke-linejoin: miter"/> @@ -12980,12 +12980,12 @@ L 252.242556 213.423828 L 252.512354 213.438718 L 252.782151 213.4475 L 253.051948 213.45038 -" clip-path="url(#p3b25755717)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p657021d3ef)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p657021d3ef)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13003,7 +13003,7 @@ L 282.252101 221.929412 L 282.252101 203.294118 L 258.806723 203.294118 z -" clip-path="url(#pedd74c87c5)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#pd88eccea27)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -13088,12 +13088,12 @@ L 280.37701 213.420285 L 280.646807 213.437162 L 280.916605 213.447115 L 281.186402 213.45038 -" clip-path="url(#pedd74c87c5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd88eccea27)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd88eccea27)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13111,7 +13111,7 @@ L 310.386555 221.929412 L 310.386555 203.294118 L 286.941176 203.294118 z -" clip-path="url(#p12d09b434c)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> +" clip-path="url(#pb2a7d86254)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> @@ -13196,12 +13196,12 @@ L 308.511464 213.436931 L 308.781261 213.444473 L 309.051058 213.448921 L 309.320856 213.45038 -" clip-path="url(#p12d09b434c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb2a7d86254)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb2a7d86254)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13219,7 +13219,7 @@ L 338.521008 221.929412 L 338.521008 203.294118 L 315.07563 203.294118 z -" clip-path="url(#p5a15d04fe4)" style="fill: #ff7171; opacity: 0.5; stroke: #ff7171; stroke-linejoin: miter"/> +" clip-path="url(#p3166264560)" style="fill: #ff7171; opacity: 0.5; stroke: #ff7171; stroke-linejoin: miter"/> @@ -13304,12 +13304,12 @@ L 336.645918 213.421942 L 336.915715 213.43789 L 337.185512 213.447295 L 337.455309 213.45038 -" clip-path="url(#p5a15d04fe4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3166264560)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3166264560)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13327,7 +13327,7 @@ L 366.655462 221.929412 L 366.655462 203.294118 L 343.210084 203.294118 z -" clip-path="url(#p359485fdd3)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> +" clip-path="url(#p9ccf1d47b4)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> @@ -13412,12 +13412,12 @@ L 364.780372 213.455306 L 365.050169 213.452543 L 365.319966 213.450914 L 365.589763 213.45038 -" clip-path="url(#p359485fdd3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9ccf1d47b4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9ccf1d47b4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13435,7 +13435,7 @@ L 394.789916 221.929412 L 394.789916 203.294118 L 371.344538 203.294118 z -" clip-path="url(#p1f182059a1)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> +" clip-path="url(#p71f4cbcb7e)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> @@ -13520,12 +13520,12 @@ L 392.914825 213.43368 L 393.184623 213.443045 L 393.45442 213.448568 L 393.724217 213.45038 -" clip-path="url(#p1f182059a1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p71f4cbcb7e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p71f4cbcb7e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13543,7 +13543,7 @@ L 422.92437 221.929412 L 422.92437 203.294118 L 399.478992 203.294118 z -" clip-path="url(#p319825c4ed)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> +" clip-path="url(#p61e1467f82)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> @@ -13628,12 +13628,12 @@ L 421.049279 213.457534 L 421.319076 213.453522 L 421.588874 213.451156 L 421.858671 213.45038 -" clip-path="url(#p319825c4ed)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p61e1467f82)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p61e1467f82)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13651,7 +13651,7 @@ L 451.058824 221.929412 L 451.058824 203.294118 L 427.613445 203.294118 z -" clip-path="url(#p0ade624abe)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p2d22d2b851)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -13736,12 +13736,12 @@ L 449.183733 213.447705 L 449.45353 213.449205 L 449.723327 213.45009 L 449.993125 213.45038 -" clip-path="url(#p0ade624abe)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d22d2b851)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d22d2b851)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13759,7 +13759,7 @@ L 479.193277 221.929412 L 479.193277 203.294118 L 455.747899 203.294118 z -" clip-path="url(#pfe56f885c4)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> +" clip-path="url(#pce6f22d3a2)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> @@ -13844,12 +13844,12 @@ L 477.318187 213.437091 L 477.587984 213.444543 L 477.857781 213.448938 L 478.127578 213.45038 -" clip-path="url(#pfe56f885c4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pce6f22d3a2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pce6f22d3a2)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13867,7 +13867,7 @@ L 507.327731 221.929412 L 507.327731 203.294118 L 483.882353 203.294118 z -" clip-path="url(#pf7ce11eb86)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#pa0e9ecb688)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -13952,12 +13952,12 @@ L 505.45264 213.45532 L 505.722438 213.45255 L 505.992235 213.450916 L 506.262032 213.45038 -" clip-path="url(#pf7ce11eb86)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa0e9ecb688)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa0e9ecb688)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13975,7 +13975,7 @@ L 535.462185 221.929412 L 535.462185 203.294118 L 512.016807 203.294118 z -" clip-path="url(#p0bc430d501)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> +" clip-path="url(#pa2d3c51202)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> @@ -14060,12 +14060,12 @@ L 533.587094 213.443344 L 533.856891 213.44729 L 534.126689 213.449617 L 534.396486 213.45038 -" clip-path="url(#p0bc430d501)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa2d3c51202)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa2d3c51202)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14083,7 +14083,7 @@ L 563.596639 221.929412 L 563.596639 203.294118 L 540.151261 203.294118 z -" clip-path="url(#p90bfe22c7b)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> +" clip-path="url(#p4761a53a8a)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> @@ -14168,12 +14168,12 @@ L 561.721548 213.445931 L 561.991345 213.448426 L 562.261142 213.449898 L 562.53094 213.45038 -" clip-path="url(#p90bfe22c7b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4761a53a8a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4761a53a8a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14191,7 +14191,7 @@ L 591.731092 221.929412 L 591.731092 203.294118 L 568.285714 203.294118 z -" clip-path="url(#p350fe7ee46)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> +" clip-path="url(#pc6951b93b0)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> @@ -14276,12 +14276,12 @@ L 589.856002 213.476501 L 590.125799 213.461852 L 590.395596 213.453214 L 590.665393 213.45038 -" clip-path="url(#p350fe7ee46)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc6951b93b0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc6951b93b0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14299,7 +14299,7 @@ L 619.865546 221.929412 L 619.865546 203.294118 L 596.420168 203.294118 z -" clip-path="url(#pfaf4395a2e)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> +" clip-path="url(#p9958381934)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> @@ -14384,12 +14384,12 @@ L 617.990456 213.464603 L 618.260253 213.456627 L 618.53005 213.451923 L 618.799847 213.45038 -" clip-path="url(#pfaf4395a2e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9958381934)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9958381934)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14407,7 +14407,7 @@ L 113.445378 244.291765 L 113.445378 225.656471 L 90 225.656471 z -" clip-path="url(#p5e32b09672)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> +" clip-path="url(#p169a929c85)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> @@ -14492,12 +14492,12 @@ L 111.570287 236.692764 L 111.840085 236.68187 L 112.109882 236.675446 L 112.379679 236.673339 -" clip-path="url(#p5e32b09672)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p169a929c85)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p169a929c85)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14515,7 +14515,7 @@ L 141.579832 244.291765 L 141.579832 225.656471 L 118.134454 225.656471 z -" clip-path="url(#pc36ba41b28)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#p097755502f)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -14600,12 +14600,12 @@ L 139.704741 236.677595 L 139.974538 236.675208 L 140.244336 236.673801 L 140.514133 236.673339 -" clip-path="url(#pc36ba41b28)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p097755502f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p097755502f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14623,7 +14623,7 @@ L 169.714286 244.291765 L 169.714286 225.656471 L 146.268908 225.656471 z -" clip-path="url(#p838e053e26)" style="fill: #adadff; opacity: 0.5; stroke: #adadff; stroke-linejoin: miter"/> +" clip-path="url(#p30bae80d5d)" style="fill: #adadff; opacity: 0.5; stroke: #adadff; stroke-linejoin: miter"/> @@ -14708,12 +14708,12 @@ L 167.839195 236.68623 L 168.108992 236.679001 L 168.378789 236.674737 L 168.648587 236.673339 -" clip-path="url(#p838e053e26)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p30bae80d5d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p30bae80d5d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14731,7 +14731,7 @@ L 197.848739 244.291765 L 197.848739 225.656471 L 174.403361 225.656471 z -" clip-path="url(#p0c5ece0f01)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> +" clip-path="url(#pae8991dd53)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> @@ -14816,12 +14816,12 @@ L 195.973649 236.683315 L 196.243446 236.67772 L 196.513243 236.674421 L 196.78304 236.673339 -" clip-path="url(#p0c5ece0f01)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pae8991dd53)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pae8991dd53)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14839,7 +14839,7 @@ L 225.983193 244.291765 L 225.983193 225.656471 L 202.537815 225.656471 z -" clip-path="url(#pc191c97d23)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> +" clip-path="url(#p9936af7547)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> @@ -14924,12 +14924,12 @@ L 224.108103 236.661119 L 224.3779 236.667972 L 224.647697 236.672013 L 224.917494 236.673339 -" clip-path="url(#pc191c97d23)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9936af7547)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9936af7547)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14947,7 +14947,7 @@ L 254.117647 244.291765 L 254.117647 225.656471 L 230.672269 225.656471 z -" clip-path="url(#p1285f97a0f)" style="fill: #ff8989; opacity: 0.5; stroke: #ff8989; stroke-linejoin: miter"/> +" clip-path="url(#pf5c7df3391)" style="fill: #ff8989; opacity: 0.5; stroke: #ff8989; stroke-linejoin: miter"/> @@ -15032,12 +15032,12 @@ L 252.242556 236.645112 L 252.512354 236.660942 L 252.782151 236.670277 L 253.051948 236.673339 -" clip-path="url(#p1285f97a0f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf5c7df3391)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf5c7df3391)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15055,7 +15055,7 @@ L 282.252101 244.291765 L 282.252101 225.656471 L 258.806723 225.656471 z -" clip-path="url(#p5b62c30e46)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> +" clip-path="url(#p365ce6389b)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> @@ -15140,12 +15140,12 @@ L 280.37701 236.659538 L 280.646807 236.667277 L 280.916605 236.671842 L 281.186402 236.673339 -" clip-path="url(#p5b62c30e46)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p365ce6389b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p365ce6389b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15163,7 +15163,7 @@ L 310.386555 244.291765 L 310.386555 225.656471 L 286.941176 225.656471 z -" clip-path="url(#pc5b1e69926)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p6c3e2fcf4a)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -15248,12 +15248,12 @@ L 308.511464 236.641078 L 308.781261 236.65917 L 309.051058 236.669839 L 309.320856 236.673339 -" clip-path="url(#pc5b1e69926)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6c3e2fcf4a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6c3e2fcf4a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15271,7 +15271,7 @@ L 338.521008 244.291765 L 338.521008 225.656471 L 315.07563 225.656471 z -" clip-path="url(#pca4e354c55)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> +" clip-path="url(#pd5ab3e846a)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> @@ -15356,12 +15356,12 @@ L 336.645918 236.652804 L 336.915715 236.66432 L 337.185512 236.671111 L 337.455309 236.673339 -" clip-path="url(#pca4e354c55)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd5ab3e846a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd5ab3e846a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15379,7 +15379,7 @@ L 366.655462 244.291765 L 366.655462 225.656471 L 343.210084 225.656471 z -" clip-path="url(#p184a513001)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> +" clip-path="url(#p6e5917034b)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> @@ -15464,12 +15464,12 @@ L 364.780372 236.669554 L 365.050169 236.671676 L 365.319966 236.672928 L 365.589763 236.673339 -" clip-path="url(#p184a513001)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6e5917034b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6e5917034b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15487,7 +15487,7 @@ L 394.789916 244.291765 L 394.789916 225.656471 L 371.344538 225.656471 z -" clip-path="url(#p7feeafe88b)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> +" clip-path="url(#pc732c08285)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> @@ -15572,12 +15572,12 @@ L 392.914825 236.666624 L 393.184623 236.67039 L 393.45442 236.67261 L 393.724217 236.673339 -" clip-path="url(#p7feeafe88b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc732c08285)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc732c08285)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15595,7 +15595,7 @@ L 422.92437 244.291765 L 422.92437 225.656471 L 399.478992 225.656471 z -" clip-path="url(#p42646b9276)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#p5d8dc2c116)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -15680,12 +15680,12 @@ L 421.049279 236.671131 L 421.319076 236.672369 L 421.588874 236.673099 L 421.858671 236.673339 -" clip-path="url(#p42646b9276)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5d8dc2c116)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5d8dc2c116)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15703,7 +15703,7 @@ L 451.058824 244.291765 L 451.058824 225.656471 L 427.613445 225.656471 z -" clip-path="url(#pe1fa7c8148)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> +" clip-path="url(#p699eb87899)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> @@ -15788,12 +15788,12 @@ L 449.183733 236.68525 L 449.45353 236.67857 L 449.723327 236.674631 L 449.993125 236.673339 -" clip-path="url(#pe1fa7c8148)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p699eb87899)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p699eb87899)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15811,7 +15811,7 @@ L 479.193277 244.291765 L 479.193277 225.656471 L 455.747899 225.656471 z -" clip-path="url(#pb74f9bce34)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> +" clip-path="url(#p56be419a4c)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> @@ -15896,12 +15896,12 @@ L 477.318187 236.671734 L 477.587984 236.672634 L 477.857781 236.673165 L 478.127578 236.673339 -" clip-path="url(#pb74f9bce34)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p56be419a4c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p56be419a4c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15919,7 +15919,7 @@ L 507.327731 244.291765 L 507.327731 225.656471 L 483.882353 225.656471 z -" clip-path="url(#pe927c12d8a)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> +" clip-path="url(#p2ca32f3500)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> @@ -16004,12 +16004,12 @@ L 505.45264 236.678984 L 505.722438 236.675818 L 505.992235 236.673951 L 506.262032 236.673339 -" clip-path="url(#pe927c12d8a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2ca32f3500)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2ca32f3500)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16027,7 +16027,7 @@ L 535.462185 244.291765 L 535.462185 225.656471 L 512.016807 225.656471 z -" clip-path="url(#p31981ca986)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> +" clip-path="url(#pe9b51270ea)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> @@ -16112,12 +16112,12 @@ L 533.587094 236.664773 L 533.856891 236.669577 L 534.126689 236.67241 L 534.396486 236.673339 -" clip-path="url(#p31981ca986)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe9b51270ea)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe9b51270ea)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16135,7 +16135,7 @@ L 563.596639 244.291765 L 563.596639 225.656471 L 540.151261 225.656471 z -" clip-path="url(#pba9577c095)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#pa41e06765d)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -16220,12 +16220,12 @@ L 561.721548 236.673188 L 561.991345 236.673273 L 562.261142 236.673323 L 562.53094 236.673339 -" clip-path="url(#pba9577c095)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa41e06765d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa41e06765d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16243,7 +16243,7 @@ L 591.731092 244.291765 L 591.731092 225.656471 L 568.285714 225.656471 z -" clip-path="url(#p9401a7888a)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> +" clip-path="url(#pe26440a59e)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> @@ -16328,12 +16328,12 @@ L 589.856002 236.695308 L 590.125799 236.682988 L 590.395596 236.675722 L 590.665393 236.673339 -" clip-path="url(#p9401a7888a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe26440a59e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe26440a59e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16351,7 +16351,7 @@ L 619.865546 244.291765 L 619.865546 225.656471 L 596.420168 225.656471 z -" clip-path="url(#p95976c6a75)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p24c067b095)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -16436,12 +16436,12 @@ L 617.990456 236.680774 L 618.260253 236.676605 L 618.53005 236.674146 L 618.799847 236.673339 -" clip-path="url(#p95976c6a75)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p24c067b095)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p24c067b095)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16459,7 +16459,7 @@ L 113.445378 266.654118 L 113.445378 248.018824 L 90 248.018824 z -" clip-path="url(#p79ff737180)" style="fill: #6565ff; opacity: 0.5; stroke: #6565ff; stroke-linejoin: miter"/> +" clip-path="url(#p8dcad32f10)" style="fill: #6565ff; opacity: 0.5; stroke: #6565ff; stroke-linejoin: miter"/> @@ -16544,12 +16544,12 @@ L 111.570287 257.534332 L 111.840085 257.52298 L 112.109882 257.516286 L 112.379679 257.51409 -" clip-path="url(#p79ff737180)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8dcad32f10)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8dcad32f10)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16567,7 +16567,7 @@ L 141.579832 266.654118 L 141.579832 248.018824 L 118.134454 248.018824 z -" clip-path="url(#p222fac9a4e)" style="fill: #ffb1b1; opacity: 0.5; stroke: #ffb1b1; stroke-linejoin: miter"/> +" clip-path="url(#p2261cbb452)" style="fill: #ffb1b1; opacity: 0.5; stroke: #ffb1b1; stroke-linejoin: miter"/> @@ -16652,12 +16652,12 @@ L 139.704741 257.502514 L 139.974538 257.509006 L 140.244336 257.512834 L 140.514133 257.51409 -" clip-path="url(#p222fac9a4e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2261cbb452)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2261cbb452)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16675,7 +16675,7 @@ L 169.714286 266.654118 L 169.714286 248.018824 L 146.268908 248.018824 z -" clip-path="url(#p3b1ba7ae44)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> +" clip-path="url(#p893b2742c9)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> @@ -16760,12 +16760,12 @@ L 167.839195 257.520305 L 168.108992 257.516819 L 168.378789 257.514764 L 168.648587 257.51409 -" clip-path="url(#p3b1ba7ae44)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p893b2742c9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p893b2742c9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16783,7 +16783,7 @@ L 197.848739 266.654118 L 197.848739 248.018824 L 174.403361 248.018824 z -" clip-path="url(#pbed35e0d9b)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> +" clip-path="url(#p0216f460b1)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> @@ -16868,12 +16868,12 @@ L 195.973649 257.523118 L 196.243446 257.518055 L 196.513243 257.515069 L 196.78304 257.51409 -" clip-path="url(#pbed35e0d9b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0216f460b1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0216f460b1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16891,7 +16891,7 @@ L 225.983193 266.654118 L 225.983193 248.018824 L 202.537815 248.018824 z -" clip-path="url(#p834b04e9f2)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#pfc9da674fe)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -16976,12 +16976,12 @@ L 224.108103 257.504542 L 224.3779 257.509896 L 224.647697 257.513054 L 224.917494 257.51409 -" clip-path="url(#p834b04e9f2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfc9da674fe)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfc9da674fe)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16999,7 +16999,7 @@ L 254.117647 266.654118 L 254.117647 248.018824 L 230.672269 248.018824 z -" clip-path="url(#pb180c56a94)" style="fill: #ffb9b9; opacity: 0.5; stroke: #ffb9b9; stroke-linejoin: miter"/> +" clip-path="url(#pb45d1bdb16)" style="fill: #ffb9b9; opacity: 0.5; stroke: #ffb9b9; stroke-linejoin: miter"/> @@ -17084,12 +17084,12 @@ L 252.242556 257.490451 L 252.512354 257.503707 L 252.782151 257.511525 L 253.051948 257.51409 -" clip-path="url(#pb180c56a94)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb45d1bdb16)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb45d1bdb16)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17107,7 +17107,7 @@ L 282.252101 266.654118 L 282.252101 248.018824 L 258.806723 248.018824 z -" clip-path="url(#p51f7139923)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> +" clip-path="url(#p79c12aad27)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> @@ -17192,12 +17192,12 @@ L 280.37701 257.507306 L 280.646807 257.51111 L 280.916605 257.513354 L 281.186402 257.51409 -" clip-path="url(#p51f7139923)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p79c12aad27)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p79c12aad27)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17215,7 +17215,7 @@ L 310.386555 266.654118 L 310.386555 248.018824 L 286.941176 248.018824 z -" clip-path="url(#p2a99b78d25)" style="fill: #ff6d6d; opacity: 0.5; stroke: #ff6d6d; stroke-linejoin: miter"/> +" clip-path="url(#p6695d3f306)" style="fill: #ff6d6d; opacity: 0.5; stroke: #ff6d6d; stroke-linejoin: miter"/> @@ -17300,12 +17300,12 @@ L 308.511464 257.492572 L 308.781261 257.504639 L 309.051058 257.511755 L 309.320856 257.51409 -" clip-path="url(#p2a99b78d25)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6695d3f306)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6695d3f306)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17323,7 +17323,7 @@ L 338.521008 266.654118 L 338.521008 248.018824 L 315.07563 248.018824 z -" clip-path="url(#p3e94110fbf)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p1623733752)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -17408,12 +17408,12 @@ L 336.645918 257.496544 L 336.915715 257.506384 L 337.185512 257.512186 L 337.455309 257.51409 -" clip-path="url(#p3e94110fbf)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1623733752)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1623733752)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17431,7 +17431,7 @@ L 366.655462 266.654118 L 366.655462 248.018824 L 343.210084 248.018824 z -" clip-path="url(#pc31e5a52c9)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> +" clip-path="url(#pb0acab58d6)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> @@ -17516,12 +17516,12 @@ L 364.780372 257.527932 L 365.050169 257.520169 L 365.319966 257.515591 L 365.589763 257.51409 -" clip-path="url(#pc31e5a52c9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb0acab58d6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb0acab58d6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17539,7 +17539,7 @@ L 394.789916 266.654118 L 394.789916 248.018824 L 371.344538 248.018824 z -" clip-path="url(#pd3377fde82)" style="fill: #ffbdbd; opacity: 0.5; stroke: #ffbdbd; stroke-linejoin: miter"/> +" clip-path="url(#pa1dd1c51e8)" style="fill: #ffbdbd; opacity: 0.5; stroke: #ffbdbd; stroke-linejoin: miter"/> @@ -17624,12 +17624,12 @@ L 392.914825 257.506353 L 393.184623 257.510692 L 393.45442 257.51325 L 393.724217 257.51409 -" clip-path="url(#pd3377fde82)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa1dd1c51e8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa1dd1c51e8)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17647,7 +17647,7 @@ L 422.92437 266.654118 L 422.92437 248.018824 L 399.478992 248.018824 z -" clip-path="url(#p76533f500f)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> +" clip-path="url(#p494ea5f514)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> @@ -17732,12 +17732,12 @@ L 421.049279 257.515663 L 421.319076 257.514781 L 421.588874 257.51426 L 421.858671 257.51409 -" clip-path="url(#p76533f500f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p494ea5f514)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p494ea5f514)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17755,7 +17755,7 @@ L 451.058824 266.654118 L 451.058824 248.018824 L 427.613445 248.018824 z -" clip-path="url(#p5851ecd812)" style="fill: #9595ff; opacity: 0.5; stroke: #9595ff; stroke-linejoin: miter"/> +" clip-path="url(#p04e15785dc)" style="fill: #9595ff; opacity: 0.5; stroke: #9595ff; stroke-linejoin: miter"/> @@ -17840,12 +17840,12 @@ L 449.183733 257.518347 L 449.45353 257.515959 L 449.723327 257.514552 L 449.993125 257.51409 -" clip-path="url(#p5851ecd812)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p04e15785dc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p04e15785dc)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17863,7 +17863,7 @@ L 479.193277 266.654118 L 479.193277 248.018824 L 455.747899 248.018824 z -" clip-path="url(#p982de1b23f)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> +" clip-path="url(#pb1ae75497e)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> @@ -17948,12 +17948,12 @@ L 477.318187 257.515027 L 477.587984 257.514501 L 477.857781 257.514191 L 478.127578 257.51409 -" clip-path="url(#p982de1b23f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb1ae75497e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb1ae75497e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17971,7 +17971,7 @@ L 507.327731 266.654118 L 507.327731 248.018824 L 483.882353 248.018824 z -" clip-path="url(#p321fe2ed74)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> +" clip-path="url(#p28840b3a41)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> @@ -18056,12 +18056,12 @@ L 505.45264 257.523423 L 505.722438 257.518189 L 505.992235 257.515102 L 506.262032 257.51409 -" clip-path="url(#p321fe2ed74)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p28840b3a41)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p28840b3a41)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18079,7 +18079,7 @@ L 535.462185 266.654118 L 535.462185 248.018824 L 512.016807 248.018824 z -" clip-path="url(#p584c4d791d)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> +" clip-path="url(#p1f3d8f83d0)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> @@ -18164,12 +18164,12 @@ L 533.587094 257.509686 L 533.856891 257.512155 L 534.126689 257.513612 L 534.396486 257.51409 -" clip-path="url(#p584c4d791d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1f3d8f83d0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1f3d8f83d0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18187,7 +18187,7 @@ L 563.596639 266.654118 L 563.596639 248.018824 L 540.151261 248.018824 z -" clip-path="url(#pd63ea8ae06)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p26b9101078)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -18272,12 +18272,12 @@ L 561.721548 257.514644 L 561.991345 257.514333 L 562.261142 257.51415 L 562.53094 257.51409 -" clip-path="url(#pd63ea8ae06)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p26b9101078)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p26b9101078)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18295,7 +18295,7 @@ L 591.731092 266.654118 L 591.731092 248.018824 L 568.285714 248.018824 z -" clip-path="url(#p50c2b28dd2)" style="fill: #7d7dff; opacity: 0.5; stroke: #7d7dff; stroke-linejoin: miter"/> +" clip-path="url(#p74415eaf6f)" style="fill: #7d7dff; opacity: 0.5; stroke: #7d7dff; stroke-linejoin: miter"/> @@ -18380,12 +18380,12 @@ L 589.856002 257.537397 L 590.125799 257.524326 L 590.395596 257.516618 L 590.665393 257.51409 -" clip-path="url(#p50c2b28dd2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p74415eaf6f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p74415eaf6f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18403,7 +18403,7 @@ L 619.865546 266.654118 L 619.865546 248.018824 L 596.420168 248.018824 z -" clip-path="url(#pb2198037c5)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> +" clip-path="url(#p13b19d2359)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> @@ -18488,12 +18488,12 @@ L 617.990456 257.52 L 618.260253 257.516686 L 618.53005 257.514731 L 618.799847 257.51409 -" clip-path="url(#pb2198037c5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p13b19d2359)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p13b19d2359)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18511,7 +18511,7 @@ L 113.445378 289.016471 L 113.445378 270.381176 L 90 270.381176 z -" clip-path="url(#pd13beb47a1)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> +" clip-path="url(#pd689110c07)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> @@ -18700,12 +18700,12 @@ L 111.570287 279.921851 L 111.840085 279.916215 L 112.109882 279.912891 L 112.379679 279.9118 -" clip-path="url(#pd13beb47a1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd689110c07)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd689110c07)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18723,7 +18723,7 @@ L 141.579832 289.016471 L 141.579832 270.381176 L 118.134454 270.381176 z -" clip-path="url(#pb38bfe5058)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> +" clip-path="url(#pd39633e402)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> @@ -18808,12 +18808,12 @@ L 139.704741 279.905144 L 139.974538 279.908877 L 140.244336 279.911078 L 140.514133 279.9118 -" clip-path="url(#pb38bfe5058)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd39633e402)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd39633e402)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18831,7 +18831,7 @@ L 169.714286 289.016471 L 169.714286 270.381176 L 146.268908 270.381176 z -" clip-path="url(#p4122ca64c1)" style="fill: #3d3dff; opacity: 0.5; stroke: #3d3dff; stroke-linejoin: miter"/> +" clip-path="url(#pf1e37fe3d7)" style="fill: #3d3dff; opacity: 0.5; stroke: #3d3dff; stroke-linejoin: miter"/> @@ -18916,12 +18916,12 @@ L 167.839195 279.922655 L 168.108992 279.916568 L 168.378789 279.912978 L 168.648587 279.9118 -" clip-path="url(#p4122ca64c1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf1e37fe3d7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf1e37fe3d7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18939,7 +18939,7 @@ L 197.848739 289.016471 L 197.848739 270.381176 L 174.403361 270.381176 z -" clip-path="url(#p22ce71372f)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> +" clip-path="url(#p0f190717d9)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> @@ -19024,12 +19024,12 @@ L 195.973649 279.916278 L 196.243446 279.913767 L 196.513243 279.912286 L 196.78304 279.9118 -" clip-path="url(#p22ce71372f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0f190717d9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0f190717d9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19047,7 +19047,7 @@ L 225.983193 289.016471 L 225.983193 270.381176 L 202.537815 270.381176 z -" clip-path="url(#p743d89218f)" style="fill: #7171ff; opacity: 0.5; stroke: #7171ff; stroke-linejoin: miter"/> +" clip-path="url(#p93715b46cf)" style="fill: #7171ff; opacity: 0.5; stroke: #7171ff; stroke-linejoin: miter"/> @@ -19132,12 +19132,12 @@ L 224.108103 279.919405 L 224.3779 279.91514 L 224.647697 279.912625 L 224.917494 279.9118 -" clip-path="url(#p743d89218f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p93715b46cf)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p93715b46cf)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19155,7 +19155,7 @@ L 254.117647 289.016471 L 254.117647 270.381176 L 230.672269 270.381176 z -" clip-path="url(#p1a3b888f52)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> +" clip-path="url(#p51e85e92c6)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> @@ -19240,12 +19240,12 @@ L 252.242556 279.90632 L 252.512354 279.909393 L 252.782151 279.911206 L 253.051948 279.9118 -" clip-path="url(#p1a3b888f52)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p51e85e92c6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p51e85e92c6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19263,7 +19263,7 @@ L 282.252101 289.016471 L 282.252101 270.381176 L 258.806723 270.381176 z -" clip-path="url(#pcbbf41ba67)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p803617f84a)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -19348,12 +19348,12 @@ L 280.37701 279.91682 L 280.646807 279.914005 L 280.916605 279.912345 L 281.186402 279.9118 -" clip-path="url(#pcbbf41ba67)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p803617f84a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p803617f84a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19371,7 +19371,7 @@ L 310.386555 289.016471 L 310.386555 270.381176 L 286.941176 270.381176 z -" clip-path="url(#p6d7c46d202)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> +" clip-path="url(#p769d05841c)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> @@ -19456,12 +19456,12 @@ L 308.511464 279.903943 L 308.781261 279.908349 L 309.051058 279.910948 L 309.320856 279.9118 -" clip-path="url(#p6d7c46d202)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p769d05841c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p769d05841c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19479,7 +19479,7 @@ L 338.521008 289.016471 L 338.521008 270.381176 L 315.07563 270.381176 z -" clip-path="url(#p74d9537168)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#pb89900e586)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -19564,12 +19564,12 @@ L 336.645918 279.899982 L 336.915715 279.90661 L 337.185512 279.910518 L 337.455309 279.9118 -" clip-path="url(#p74d9537168)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb89900e586)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb89900e586)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19587,7 +19587,7 @@ L 366.655462 289.016471 L 366.655462 270.381176 L 343.210084 270.381176 z -" clip-path="url(#p8802b64485)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p98b85104e0)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -19672,12 +19672,12 @@ L 364.780372 279.914681 L 365.050169 279.913066 L 365.319966 279.912113 L 365.589763 279.9118 -" clip-path="url(#p8802b64485)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p98b85104e0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p98b85104e0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19695,7 +19695,7 @@ L 394.789916 289.016471 L 394.789916 270.381176 L 371.344538 270.381176 z -" clip-path="url(#pea4849c85f)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> +" clip-path="url(#p4353aa2a27)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> @@ -19780,12 +19780,12 @@ L 392.914825 279.911205 L 393.184623 279.911539 L 393.45442 279.911736 L 393.724217 279.9118 -" clip-path="url(#pea4849c85f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4353aa2a27)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4353aa2a27)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19803,7 +19803,7 @@ L 422.92437 289.016471 L 422.92437 270.381176 L 399.478992 270.381176 z -" clip-path="url(#p3e745a99da)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> +" clip-path="url(#pf4789c4823)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> @@ -19888,12 +19888,12 @@ L 421.049279 279.907792 L 421.319076 279.91004 L 421.588874 279.911366 L 421.858671 279.9118 -" clip-path="url(#p3e745a99da)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf4789c4823)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf4789c4823)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19911,7 +19911,7 @@ L 451.058824 289.016471 L 451.058824 270.381176 L 427.613445 270.381176 z -" clip-path="url(#p4b9a4f0b7e)" style="fill: #8585ff; opacity: 0.5; stroke: #8585ff; stroke-linejoin: miter"/> +" clip-path="url(#p4e8c82aff9)" style="fill: #8585ff; opacity: 0.5; stroke: #8585ff; stroke-linejoin: miter"/> @@ -19996,12 +19996,12 @@ L 449.183733 279.918591 L 449.45353 279.914783 L 449.723327 279.912537 L 449.993125 279.9118 -" clip-path="url(#p4b9a4f0b7e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4e8c82aff9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4e8c82aff9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20019,7 +20019,7 @@ L 479.193277 289.016471 L 479.193277 270.381176 L 455.747899 270.381176 z -" clip-path="url(#p8dfa4bae98)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> +" clip-path="url(#p1ca7f637e6)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> @@ -20104,12 +20104,12 @@ L 477.318187 279.904075 L 477.587984 279.908407 L 477.857781 279.910962 L 478.127578 279.9118 -" clip-path="url(#p8dfa4bae98)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1ca7f637e6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1ca7f637e6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20127,7 +20127,7 @@ L 507.327731 289.016471 L 507.327731 270.381176 L 483.882353 270.381176 z -" clip-path="url(#pbed16833d3)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> +" clip-path="url(#pe67a9c4e66)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> @@ -20212,12 +20212,12 @@ L 505.45264 279.914063 L 505.722438 279.912794 L 505.992235 279.912046 L 506.262032 279.9118 -" clip-path="url(#pbed16833d3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe67a9c4e66)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe67a9c4e66)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20235,7 +20235,7 @@ L 535.462185 289.016471 L 535.462185 270.381176 L 512.016807 270.381176 z -" clip-path="url(#p5058b5c7d8)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> +" clip-path="url(#p5f097ece06)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> @@ -20320,12 +20320,12 @@ L 533.587094 279.908496 L 533.856891 279.910349 L 534.126689 279.911442 L 534.396486 279.9118 -" clip-path="url(#p5058b5c7d8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5f097ece06)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5f097ece06)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20343,7 +20343,7 @@ L 563.596639 289.016471 L 563.596639 270.381176 L 540.151261 270.381176 z -" clip-path="url(#p775114c6f6)" style="fill: #adadff; opacity: 0.5; stroke: #adadff; stroke-linejoin: miter"/> +" clip-path="url(#p0ac198ccf9)" style="fill: #adadff; opacity: 0.5; stroke: #adadff; stroke-linejoin: miter"/> @@ -20428,12 +20428,12 @@ L 561.721548 279.909286 L 561.991345 279.910696 L 562.261142 279.911528 L 562.53094 279.9118 -" clip-path="url(#p775114c6f6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0ac198ccf9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0ac198ccf9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20451,7 +20451,7 @@ L 591.731092 289.016471 L 591.731092 270.381176 L 568.285714 270.381176 z -" clip-path="url(#pdde563aecb)" style="fill: #0000d0; opacity: 0.5; stroke: #0000d0; stroke-linejoin: miter"/> +" clip-path="url(#p384b71cb83)" style="fill: #0000d0; opacity: 0.5; stroke: #0000d0; stroke-linejoin: miter"/> @@ -20536,12 +20536,12 @@ L 589.856002 279.938338 L 590.125799 279.923456 L 590.395596 279.914679 L 590.665393 279.9118 -" clip-path="url(#pdde563aecb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p384b71cb83)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p384b71cb83)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20559,7 +20559,7 @@ L 619.865546 289.016471 L 619.865546 270.381176 L 596.420168 270.381176 z -" clip-path="url(#p3ba50efa49)" style="fill: #6969ff; opacity: 0.5; stroke: #6969ff; stroke-linejoin: miter"/> +" clip-path="url(#p2f57205f3c)" style="fill: #6969ff; opacity: 0.5; stroke: #6969ff; stroke-linejoin: miter"/> @@ -20644,12 +20644,12 @@ L 617.990456 279.923673 L 618.260253 279.917015 L 618.53005 279.913088 L 618.799847 279.9118 -" clip-path="url(#p3ba50efa49)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2f57205f3c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2f57205f3c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20667,7 +20667,7 @@ L 113.445378 311.378824 L 113.445378 292.743529 L 90 292.743529 z -" clip-path="url(#p31ba56f630)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p34af66d8fe)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -20752,12 +20752,12 @@ L 111.570287 301.001916 L 111.840085 300.997827 L 112.109882 300.995415 L 112.379679 300.994624 -" clip-path="url(#p31ba56f630)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p34af66d8fe)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p34af66d8fe)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20775,7 +20775,7 @@ L 141.579832 311.378824 L 141.579832 292.743529 L 118.134454 292.743529 z -" clip-path="url(#pb1fd7d7415)" style="fill: #fffdfd; opacity: 0.5; stroke: #fffdfd; stroke-linejoin: miter"/> +" clip-path="url(#p9dc423476a)" style="fill: #fffdfd; opacity: 0.5; stroke: #fffdfd; stroke-linejoin: miter"/> @@ -20860,12 +20860,12 @@ L 139.704741 300.991346 L 139.974538 300.993185 L 140.244336 300.994269 L 140.514133 300.994624 -" clip-path="url(#pb1fd7d7415)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9dc423476a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9dc423476a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20883,7 +20883,7 @@ L 169.714286 311.378824 L 169.714286 292.743529 L 146.268908 292.743529 z -" clip-path="url(#p993d086794)" style="fill: #0000b4; opacity: 0.5; stroke: #0000b4; stroke-linejoin: miter"/> +" clip-path="url(#p643e0a1be3)" style="fill: #0000b4; opacity: 0.5; stroke: #0000b4; stroke-linejoin: miter"/> @@ -20968,12 +20968,12 @@ L 167.839195 301.010657 L 168.108992 301.001666 L 168.378789 300.996364 L 168.648587 300.994624 -" clip-path="url(#p993d086794)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p643e0a1be3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p643e0a1be3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20991,7 +20991,7 @@ L 197.848739 311.378824 L 197.848739 292.743529 L 174.403361 292.743529 z -" clip-path="url(#pa6b2d8b2f3)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> +" clip-path="url(#p1141eee0a5)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> @@ -21076,12 +21076,12 @@ L 195.973649 301.005225 L 196.243446 300.99928 L 196.513243 300.995774 L 196.78304 300.994624 -" clip-path="url(#pa6b2d8b2f3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1141eee0a5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1141eee0a5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21099,7 +21099,7 @@ L 225.983193 311.378824 L 225.983193 292.743529 L 202.537815 292.743529 z -" clip-path="url(#pac4e887efc)" style="fill: #2d2dff; opacity: 0.5; stroke: #2d2dff; stroke-linejoin: miter"/> +" clip-path="url(#pd48ecf06da)" style="fill: #2d2dff; opacity: 0.5; stroke: #2d2dff; stroke-linejoin: miter"/> @@ -21184,12 +21184,12 @@ L 224.108103 301.004492 L 224.3779 300.998958 L 224.647697 300.995695 L 224.917494 300.994624 -" clip-path="url(#pac4e887efc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd48ecf06da)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd48ecf06da)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21207,7 +21207,7 @@ L 254.117647 311.378824 L 254.117647 292.743529 L 230.672269 292.743529 z -" clip-path="url(#p501d1fca1f)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> +" clip-path="url(#p267f409bc7)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> @@ -21292,12 +21292,12 @@ L 252.242556 300.991764 L 252.512354 300.993368 L 252.782151 300.994314 L 253.051948 300.994624 -" clip-path="url(#p501d1fca1f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p267f409bc7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p267f409bc7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21315,7 +21315,7 @@ L 282.252101 311.378824 L 282.252101 292.743529 L 258.806723 292.743529 z -" clip-path="url(#pd8e8c6a65a)" style="fill: #ddddff; opacity: 0.5; stroke: #ddddff; stroke-linejoin: miter"/> +" clip-path="url(#p905f8f9d64)" style="fill: #ddddff; opacity: 0.5; stroke: #ddddff; stroke-linejoin: miter"/> @@ -21400,12 +21400,12 @@ L 280.37701 300.999115 L 280.646807 300.996597 L 280.916605 300.995112 L 281.186402 300.994624 -" clip-path="url(#pd8e8c6a65a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p905f8f9d64)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p905f8f9d64)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21423,7 +21423,7 @@ L 310.386555 311.378824 L 310.386555 292.743529 L 286.941176 292.743529 z -" clip-path="url(#pdb1424c883)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> +" clip-path="url(#pcc401b23d6)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> @@ -21508,12 +21508,12 @@ L 308.511464 300.996323 L 308.781261 300.99537 L 309.051058 300.994809 L 309.320856 300.994624 -" clip-path="url(#pdb1424c883)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcc401b23d6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcc401b23d6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21531,7 +21531,7 @@ L 338.521008 311.378824 L 338.521008 292.743529 L 315.07563 292.743529 z -" clip-path="url(#p656cf547b5)" style="fill: #ffd1d1; opacity: 0.5; stroke: #ffd1d1; stroke-linejoin: miter"/> +" clip-path="url(#p6a274e6637)" style="fill: #ffd1d1; opacity: 0.5; stroke: #ffd1d1; stroke-linejoin: miter"/> @@ -21616,12 +21616,12 @@ L 336.645918 300.990047 L 336.915715 300.992614 L 337.185512 300.994128 L 337.455309 300.994624 -" clip-path="url(#p656cf547b5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6a274e6637)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6a274e6637)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21639,7 +21639,7 @@ L 366.655462 311.378824 L 366.655462 292.743529 L 343.210084 292.743529 z -" clip-path="url(#pe3d6817b3f)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p6d13d72b0d)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -21724,12 +21724,12 @@ L 364.780372 300.994484 L 365.050169 300.994563 L 365.319966 300.994609 L 365.589763 300.994624 -" clip-path="url(#pe3d6817b3f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6d13d72b0d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6d13d72b0d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21747,7 +21747,7 @@ L 394.789916 311.378824 L 394.789916 292.743529 L 371.344538 292.743529 z -" clip-path="url(#p9188dc1c9e)" style="fill: #ff5959; opacity: 0.5; stroke: #ff5959; stroke-linejoin: miter"/> +" clip-path="url(#pd8da9fe289)" style="fill: #ff5959; opacity: 0.5; stroke: #ff5959; stroke-linejoin: miter"/> @@ -21832,12 +21832,12 @@ L 392.914825 300.993743 L 393.184623 300.994237 L 393.45442 300.994529 L 393.724217 300.994624 -" clip-path="url(#p9188dc1c9e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd8da9fe289)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd8da9fe289)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21855,7 +21855,7 @@ L 422.92437 311.378824 L 422.92437 292.743529 L 399.478992 292.743529 z -" clip-path="url(#pdb44af7f3e)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#pb326fe52a0)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -21940,12 +21940,12 @@ L 421.049279 300.99139 L 421.319076 300.993204 L 421.588874 300.994273 L 421.858671 300.994624 -" clip-path="url(#pdb44af7f3e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb326fe52a0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb326fe52a0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21963,7 +21963,7 @@ L 451.058824 311.378824 L 451.058824 292.743529 L 427.613445 292.743529 z -" clip-path="url(#p4d04445704)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> +" clip-path="url(#p18e4a0741e)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> @@ -22048,12 +22048,12 @@ L 449.183733 300.990506 L 449.45353 300.992816 L 449.723327 300.994178 L 449.993125 300.994624 -" clip-path="url(#p4d04445704)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p18e4a0741e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p18e4a0741e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22071,7 +22071,7 @@ L 479.193277 311.378824 L 479.193277 292.743529 L 455.747899 292.743529 z -" clip-path="url(#pb9bdfa073d)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> +" clip-path="url(#pcb50a10722)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> @@ -22156,12 +22156,12 @@ L 477.318187 300.990817 L 477.587984 300.992952 L 477.857781 300.994211 L 478.127578 300.994624 -" clip-path="url(#pb9bdfa073d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcb50a10722)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcb50a10722)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22179,7 +22179,7 @@ L 507.327731 311.378824 L 507.327731 292.743529 L 483.882353 292.743529 z -" clip-path="url(#pf2686785c2)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> +" clip-path="url(#p5f3b3d9601)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> @@ -22264,12 +22264,12 @@ L 505.45264 300.995656 L 505.722438 300.995078 L 505.992235 300.994736 L 506.262032 300.994624 -" clip-path="url(#pf2686785c2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5f3b3d9601)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5f3b3d9601)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22287,7 +22287,7 @@ L 535.462185 311.378824 L 535.462185 292.743529 L 512.016807 292.743529 z -" clip-path="url(#pbf03fc8eff)" style="fill: #ffc5c5; opacity: 0.5; stroke: #ffc5c5; stroke-linejoin: miter"/> +" clip-path="url(#p0638888184)" style="fill: #ffc5c5; opacity: 0.5; stroke: #ffc5c5; stroke-linejoin: miter"/> @@ -22372,12 +22372,12 @@ L 533.587094 300.993413 L 533.856891 300.994092 L 534.126689 300.994493 L 534.396486 300.994624 -" clip-path="url(#pbf03fc8eff)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0638888184)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0638888184)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22395,7 +22395,7 @@ L 563.596639 311.378824 L 563.596639 292.743529 L 540.151261 292.743529 z -" clip-path="url(#p2510adce9c)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> +" clip-path="url(#p3a13aa791d)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> @@ -22480,12 +22480,12 @@ L 561.721548 300.995005 L 561.991345 300.994792 L 562.261142 300.994666 L 562.53094 300.994624 -" clip-path="url(#p2510adce9c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3a13aa791d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3a13aa791d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22503,7 +22503,7 @@ L 591.731092 311.378824 L 591.731092 292.743529 L 568.285714 292.743529 z -" clip-path="url(#pbc8f0a6a81)" style="fill: #00004c; opacity: 0.5; stroke: #00004c; stroke-linejoin: miter"/> +" clip-path="url(#p2aeb4111ce)" style="fill: #00004c; opacity: 0.5; stroke: #00004c; stroke-linejoin: miter"/> @@ -22588,12 +22588,12 @@ L 589.856002 301.024648 L 590.125799 301.007811 L 590.395596 300.997881 L 590.665393 300.994624 -" clip-path="url(#pbc8f0a6a81)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2aeb4111ce)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2aeb4111ce)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22611,7 +22611,7 @@ L 619.865546 311.378824 L 619.865546 292.743529 L 596.420168 292.743529 z -" clip-path="url(#p02c33523f5)" style="fill: #2525ff; opacity: 0.5; stroke: #2525ff; stroke-linejoin: miter"/> +" clip-path="url(#p8736998af9)" style="fill: #2525ff; opacity: 0.5; stroke: #2525ff; stroke-linejoin: miter"/> @@ -22696,12 +22696,12 @@ L 617.990456 301.007524 L 618.260253 301.00029 L 618.53005 300.996024 L 618.799847 300.994624 -" clip-path="url(#p02c33523f5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8736998af9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8736998af9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22719,7 +22719,7 @@ L 113.445378 333.741176 L 113.445378 315.105882 L 90 315.105882 z -" clip-path="url(#p338771a35d)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p818416edc7)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -22804,12 +22804,12 @@ L 111.570287 322.525789 L 111.840085 322.528704 L 112.109882 322.530424 L 112.379679 322.530988 -" clip-path="url(#p338771a35d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p818416edc7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p818416edc7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22827,7 +22827,7 @@ L 141.579832 333.741176 L 141.579832 315.105882 L 118.134454 315.105882 z -" clip-path="url(#p40bd52e71e)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> +" clip-path="url(#p5f1fe7b4e5)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> @@ -22912,12 +22912,12 @@ L 139.704741 322.531749 L 139.974538 322.531322 L 140.244336 322.531071 L 140.514133 322.530988 -" clip-path="url(#p40bd52e71e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5f1fe7b4e5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5f1fe7b4e5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22935,7 +22935,7 @@ L 169.714286 333.741176 L 169.714286 315.105882 L 146.268908 315.105882 z -" clip-path="url(#pfafb0da3d0)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> +" clip-path="url(#p0d3344e6fb)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> @@ -23020,12 +23020,12 @@ L 167.839195 322.529704 L 168.108992 322.530424 L 168.378789 322.530849 L 168.648587 322.530988 -" clip-path="url(#pfafb0da3d0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0d3344e6fb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0d3344e6fb)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23043,7 +23043,7 @@ L 197.848739 333.741176 L 197.848739 315.105882 L 174.403361 315.105882 z -" clip-path="url(#pca85ac3120)" style="fill: #ff5959; opacity: 0.5; stroke: #ff5959; stroke-linejoin: miter"/> +" clip-path="url(#pf838414fe5)" style="fill: #ff5959; opacity: 0.5; stroke: #ff5959; stroke-linejoin: miter"/> @@ -23128,12 +23128,12 @@ L 195.973649 322.526742 L 196.243446 322.529123 L 196.513243 322.530527 L 196.78304 322.530988 -" clip-path="url(#pca85ac3120)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf838414fe5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf838414fe5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23151,7 +23151,7 @@ L 225.983193 333.741176 L 225.983193 315.105882 L 202.537815 315.105882 z -" clip-path="url(#pda4e6de3e0)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> +" clip-path="url(#p2d53ab164b)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> @@ -23236,12 +23236,12 @@ L 224.108103 322.535822 L 224.3779 322.533111 L 224.647697 322.531512 L 224.917494 322.530988 -" clip-path="url(#pda4e6de3e0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d53ab164b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d53ab164b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23259,7 +23259,7 @@ L 254.117647 333.741176 L 254.117647 315.105882 L 230.672269 315.105882 z -" clip-path="url(#p34475f45d1)" style="fill: #2d2dff; opacity: 0.5; stroke: #2d2dff; stroke-linejoin: miter"/> +" clip-path="url(#p10e2901bda)" style="fill: #2d2dff; opacity: 0.5; stroke: #2d2dff; stroke-linejoin: miter"/> @@ -23344,12 +23344,12 @@ L 252.242556 322.541348 L 252.512354 322.535538 L 252.782151 322.532112 L 253.051948 322.530988 -" clip-path="url(#p34475f45d1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10e2901bda)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10e2901bda)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23367,7 +23367,7 @@ L 282.252101 333.741176 L 282.252101 315.105882 L 258.806723 315.105882 z -" clip-path="url(#p3284d6dfe4)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> +" clip-path="url(#p0cf1f47fd3)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> @@ -23452,12 +23452,12 @@ L 280.37701 322.538457 L 280.646807 322.534268 L 280.916605 322.531798 L 281.186402 322.530988 -" clip-path="url(#p3284d6dfe4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0cf1f47fd3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0cf1f47fd3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23475,7 +23475,7 @@ L 310.386555 333.741176 L 310.386555 315.105882 L 286.941176 315.105882 z -" clip-path="url(#pa78dfab9d1)" style="fill: #0000fa; opacity: 0.5; stroke: #0000fa; stroke-linejoin: miter"/> +" clip-path="url(#p2ab482a533)" style="fill: #0000fa; opacity: 0.5; stroke: #0000fa; stroke-linejoin: miter"/> @@ -23560,12 +23560,12 @@ L 308.511464 322.54799 L 308.781261 322.538455 L 309.051058 322.532832 L 309.320856 322.530988 -" clip-path="url(#pa78dfab9d1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2ab482a533)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2ab482a533)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23583,7 +23583,7 @@ L 338.521008 333.741176 L 338.521008 315.105882 L 315.07563 315.105882 z -" clip-path="url(#pfb86c750db)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> +" clip-path="url(#pd6c75b88b2)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> @@ -23668,12 +23668,12 @@ L 336.645918 322.539368 L 336.915715 322.534668 L 337.185512 322.531897 L 337.455309 322.530988 -" clip-path="url(#pfb86c750db)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd6c75b88b2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd6c75b88b2)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23691,7 +23691,7 @@ L 366.655462 333.741176 L 366.655462 315.105882 L 343.210084 315.105882 z -" clip-path="url(#pa40201568c)" style="fill: #ffb9b9; opacity: 0.5; stroke: #ffb9b9; stroke-linejoin: miter"/> +" clip-path="url(#pf39fc450f2)" style="fill: #ffb9b9; opacity: 0.5; stroke: #ffb9b9; stroke-linejoin: miter"/> @@ -23776,12 +23776,12 @@ L 364.780372 322.529654 L 365.050169 322.530402 L 365.319966 322.530843 L 365.589763 322.530988 -" clip-path="url(#pa40201568c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf39fc450f2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf39fc450f2)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23799,7 +23799,7 @@ L 394.789916 333.741176 L 394.789916 315.105882 L 371.344538 315.105882 z -" clip-path="url(#pf5dca63105)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> +" clip-path="url(#pab320155e9)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> @@ -23884,12 +23884,12 @@ L 392.914825 322.529935 L 393.184623 322.530526 L 393.45442 322.530874 L 393.724217 322.530988 -" clip-path="url(#pf5dca63105)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pab320155e9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pab320155e9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23907,7 +23907,7 @@ L 422.92437 333.741176 L 422.92437 315.105882 L 399.478992 315.105882 z -" clip-path="url(#pdf97e61046)" style="fill: #ff9595; opacity: 0.5; stroke: #ff9595; stroke-linejoin: miter"/> +" clip-path="url(#p0104bb5c11)" style="fill: #ff9595; opacity: 0.5; stroke: #ff9595; stroke-linejoin: miter"/> @@ -23992,12 +23992,12 @@ L 421.049279 322.527167 L 421.319076 322.52931 L 421.588874 322.530574 L 421.858671 322.530988 -" clip-path="url(#pdf97e61046)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0104bb5c11)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0104bb5c11)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24015,7 +24015,7 @@ L 451.058824 333.741176 L 451.058824 315.105882 L 427.613445 315.105882 z -" clip-path="url(#pa6eba3b976)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#pd72c6ff218)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -24100,12 +24100,12 @@ L 449.183733 322.532624 L 449.45353 322.531707 L 449.723327 322.531166 L 449.993125 322.530988 -" clip-path="url(#pa6eba3b976)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd72c6ff218)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd72c6ff218)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24123,7 +24123,7 @@ L 479.193277 333.741176 L 479.193277 315.105882 L 455.747899 315.105882 z -" clip-path="url(#pca2b78c532)" style="fill: #ff6969; opacity: 0.5; stroke: #ff6969; stroke-linejoin: miter"/> +" clip-path="url(#p2e9515d7a2)" style="fill: #ff6969; opacity: 0.5; stroke: #ff6969; stroke-linejoin: miter"/> @@ -24208,12 +24208,12 @@ L 477.318187 322.52435 L 477.587984 322.528073 L 477.857781 322.530268 L 478.127578 322.530988 -" clip-path="url(#pca2b78c532)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2e9515d7a2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2e9515d7a2)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24231,7 +24231,7 @@ L 507.327731 333.741176 L 507.327731 315.105882 L 483.882353 315.105882 z -" clip-path="url(#p41e2599490)" style="fill: #ff9595; opacity: 0.5; stroke: #ff9595; stroke-linejoin: miter"/> +" clip-path="url(#pf9b37ef074)" style="fill: #ff9595; opacity: 0.5; stroke: #ff9595; stroke-linejoin: miter"/> @@ -24316,12 +24316,12 @@ L 505.45264 322.525609 L 505.722438 322.528626 L 505.992235 322.530405 L 506.262032 322.530988 -" clip-path="url(#p41e2599490)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf9b37ef074)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf9b37ef074)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24339,7 +24339,7 @@ L 535.462185 333.741176 L 535.462185 315.105882 L 512.016807 315.105882 z -" clip-path="url(#p1ec48641c0)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> +" clip-path="url(#p35605e1517)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> @@ -24424,12 +24424,12 @@ L 533.587094 322.528155 L 533.856891 322.529744 L 534.126689 322.530681 L 534.396486 322.530988 -" clip-path="url(#p1ec48641c0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p35605e1517)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p35605e1517)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24447,7 +24447,7 @@ L 563.596639 333.741176 L 563.596639 315.105882 L 540.151261 315.105882 z -" clip-path="url(#p4627f3e74a)" style="fill: #c9c9ff; opacity: 0.5; stroke: #c9c9ff; stroke-linejoin: miter"/> +" clip-path="url(#p95a10a362d)" style="fill: #c9c9ff; opacity: 0.5; stroke: #c9c9ff; stroke-linejoin: miter"/> @@ -24532,12 +24532,12 @@ L 561.721548 322.531563 L 561.991345 322.531241 L 562.261142 322.53105 L 562.53094 322.530988 -" clip-path="url(#p4627f3e74a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p95a10a362d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p95a10a362d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24555,7 +24555,7 @@ L 591.731092 333.741176 L 591.731092 315.105882 L 568.285714 315.105882 z -" clip-path="url(#pb4c9c845f6)" style="fill: #000055; opacity: 0.5; stroke: #000055; stroke-linejoin: miter"/> +" clip-path="url(#pcbb3a3518a)" style="fill: #000055; opacity: 0.5; stroke: #000055; stroke-linejoin: miter"/> @@ -24640,12 +24640,12 @@ L 589.856002 322.561348 L 590.125799 322.544322 L 590.395596 322.534282 L 590.665393 322.530988 -" clip-path="url(#pb4c9c845f6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcbb3a3518a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcbb3a3518a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24663,7 +24663,7 @@ L 619.865546 333.741176 L 619.865546 315.105882 L 596.420168 315.105882 z -" clip-path="url(#p1cd8d67bc4)" style="fill: #1919ff; opacity: 0.5; stroke: #1919ff; stroke-linejoin: miter"/> +" clip-path="url(#p716ed173e9)" style="fill: #1919ff; opacity: 0.5; stroke: #1919ff; stroke-linejoin: miter"/> @@ -24748,12 +24748,12 @@ L 617.990456 322.545023 L 618.260253 322.537152 L 618.53005 322.532511 L 618.799847 322.530988 -" clip-path="url(#p1cd8d67bc4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p716ed173e9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p716ed173e9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24771,7 +24771,7 @@ L 113.445378 356.103529 L 113.445378 337.468235 L 90 337.468235 z -" clip-path="url(#pf7488aa57b)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> +" clip-path="url(#p50b0a2a44e)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> @@ -24856,12 +24856,12 @@ L 111.570287 347.58233 L 111.840085 347.577814 L 112.109882 347.575151 L 112.379679 347.574277 -" clip-path="url(#pf7488aa57b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p50b0a2a44e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p50b0a2a44e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24879,7 +24879,7 @@ L 141.579832 356.103529 L 141.579832 337.468235 L 118.134454 337.468235 z -" clip-path="url(#pde57e87b2b)" style="fill: #6969ff; opacity: 0.5; stroke: #6969ff; stroke-linejoin: miter"/> +" clip-path="url(#p805609aecd)" style="fill: #6969ff; opacity: 0.5; stroke: #6969ff; stroke-linejoin: miter"/> @@ -24964,12 +24964,12 @@ L 139.704741 347.586485 L 139.974538 347.579639 L 140.244336 347.575602 L 140.514133 347.574277 -" clip-path="url(#pde57e87b2b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p805609aecd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p805609aecd)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24987,7 +24987,7 @@ L 169.714286 356.103529 L 169.714286 337.468235 L 146.268908 337.468235 z -" clip-path="url(#pc1242d518d)" style="fill: #5151ff; opacity: 0.5; stroke: #5151ff; stroke-linejoin: miter"/> +" clip-path="url(#p5307852d9c)" style="fill: #5151ff; opacity: 0.5; stroke: #5151ff; stroke-linejoin: miter"/> @@ -25072,12 +25072,12 @@ L 167.839195 347.593386 L 168.108992 347.58267 L 168.378789 347.57635 L 168.648587 347.574277 -" clip-path="url(#pc1242d518d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5307852d9c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5307852d9c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25095,7 +25095,7 @@ L 197.848739 356.103529 L 197.848739 337.468235 L 174.403361 337.468235 z -" clip-path="url(#pfefd0b8d6f)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#p7124eec22d)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -25180,12 +25180,12 @@ L 195.973649 347.577055 L 196.243446 347.575497 L 196.513243 347.574579 L 196.78304 347.574277 -" clip-path="url(#pfefd0b8d6f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7124eec22d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7124eec22d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25203,7 +25203,7 @@ L 225.983193 356.103529 L 225.983193 337.468235 L 202.537815 337.468235 z -" clip-path="url(#peb0e63fe32)" style="fill: #0000de; opacity: 0.5; stroke: #0000de; stroke-linejoin: miter"/> +" clip-path="url(#pe3a24c1499)" style="fill: #0000de; opacity: 0.5; stroke: #0000de; stroke-linejoin: miter"/> @@ -25288,12 +25288,12 @@ L 224.108103 347.595181 L 224.3779 347.583458 L 224.647697 347.576545 L 224.917494 347.574277 -" clip-path="url(#peb0e63fe32)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe3a24c1499)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe3a24c1499)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25311,7 +25311,7 @@ L 254.117647 356.103529 L 254.117647 337.468235 L 230.672269 337.468235 z -" clip-path="url(#p17d4826184)" style="fill: #0505ff; opacity: 0.5; stroke: #0505ff; stroke-linejoin: miter"/> +" clip-path="url(#p210bf0a2de)" style="fill: #0505ff; opacity: 0.5; stroke: #0505ff; stroke-linejoin: miter"/> @@ -25396,12 +25396,12 @@ L 252.242556 347.594712 L 252.512354 347.583252 L 252.782151 347.576494 L 253.051948 347.574277 -" clip-path="url(#p17d4826184)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p210bf0a2de)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p210bf0a2de)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25419,7 +25419,7 @@ L 282.252101 356.103529 L 282.252101 337.468235 L 258.806723 337.468235 z -" clip-path="url(#pb95a272886)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> +" clip-path="url(#pd1375159d0)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> @@ -25504,12 +25504,12 @@ L 280.37701 347.581915 L 280.646807 347.577632 L 280.916605 347.575106 L 281.186402 347.574277 -" clip-path="url(#pb95a272886)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd1375159d0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd1375159d0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25527,7 +25527,7 @@ L 310.386555 356.103529 L 310.386555 337.468235 L 286.941176 337.468235 z -" clip-path="url(#p184f8271e3)" style="fill: #4d4dff; opacity: 0.5; stroke: #4d4dff; stroke-linejoin: miter"/> +" clip-path="url(#p9192637b45)" style="fill: #4d4dff; opacity: 0.5; stroke: #4d4dff; stroke-linejoin: miter"/> @@ -25612,12 +25612,12 @@ L 308.511464 347.591438 L 308.781261 347.581815 L 309.051058 347.576139 L 309.320856 347.574277 -" clip-path="url(#p184f8271e3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9192637b45)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9192637b45)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25635,7 +25635,7 @@ L 338.521008 356.103529 L 338.521008 337.468235 L 315.07563 337.468235 z -" clip-path="url(#pfebdfae7f2)" style="fill: #1d1dff; opacity: 0.5; stroke: #1d1dff; stroke-linejoin: miter"/> +" clip-path="url(#pc0bd8d9a44)" style="fill: #1d1dff; opacity: 0.5; stroke: #1d1dff; stroke-linejoin: miter"/> @@ -25720,12 +25720,12 @@ L 336.645918 347.588832 L 336.915715 347.58067 L 337.185512 347.575856 L 337.455309 347.574277 -" clip-path="url(#pfebdfae7f2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc0bd8d9a44)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc0bd8d9a44)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25743,7 +25743,7 @@ L 366.655462 356.103529 L 366.655462 337.468235 L 343.210084 337.468235 z -" clip-path="url(#p725781575b)" style="fill: #4545ff; opacity: 0.5; stroke: #4545ff; stroke-linejoin: miter"/> +" clip-path="url(#p4c6675d46e)" style="fill: #4545ff; opacity: 0.5; stroke: #4545ff; stroke-linejoin: miter"/> @@ -25828,12 +25828,12 @@ L 364.780372 347.583411 L 365.050169 347.578289 L 365.319966 347.575268 L 365.589763 347.574277 -" clip-path="url(#p725781575b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4c6675d46e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4c6675d46e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25851,7 +25851,7 @@ L 394.789916 356.103529 L 394.789916 337.468235 L 371.344538 337.468235 z -" clip-path="url(#p79aec6d8a9)" style="fill: #ffd5d5; opacity: 0.5; stroke: #ffd5d5; stroke-linejoin: miter"/> +" clip-path="url(#pd54b96efe5)" style="fill: #ffd5d5; opacity: 0.5; stroke: #ffd5d5; stroke-linejoin: miter"/> @@ -25936,12 +25936,12 @@ L 392.914825 347.572295 L 393.184623 347.573407 L 393.45442 347.574062 L 393.724217 347.574277 -" clip-path="url(#p79aec6d8a9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd54b96efe5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd54b96efe5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25959,7 +25959,7 @@ L 422.92437 356.103529 L 422.92437 337.468235 L 399.478992 337.468235 z -" clip-path="url(#p745183c988)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#pd71d464646)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -26044,12 +26044,12 @@ L 421.049279 347.575632 L 421.319076 347.574872 L 421.588874 347.574424 L 421.858671 347.574277 -" clip-path="url(#p745183c988)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd71d464646)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd71d464646)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26067,7 +26067,7 @@ L 451.058824 356.103529 L 451.058824 337.468235 L 427.613445 337.468235 z -" clip-path="url(#p1ad342bee9)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p573f45905d)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -26152,12 +26152,12 @@ L 449.183733 347.570467 L 449.45353 347.572604 L 449.723327 347.573864 L 449.993125 347.574277 -" clip-path="url(#p1ad342bee9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p573f45905d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p573f45905d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26175,7 +26175,7 @@ L 479.193277 356.103529 L 479.193277 337.468235 L 455.747899 337.468235 z -" clip-path="url(#p06437e0cb9)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> +" clip-path="url(#p857f4b52a0)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> @@ -26260,12 +26260,12 @@ L 477.318187 347.574144 L 477.587984 347.574219 L 477.857781 347.574263 L 478.127578 347.574277 -" clip-path="url(#p06437e0cb9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p857f4b52a0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p857f4b52a0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26283,7 +26283,7 @@ L 507.327731 356.103529 L 507.327731 337.468235 L 483.882353 337.468235 z -" clip-path="url(#p280dd08963)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> +" clip-path="url(#p62fc16713e)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> @@ -26368,12 +26368,12 @@ L 505.45264 347.572207 L 505.722438 347.573368 L 505.992235 347.574053 L 506.262032 347.574277 -" clip-path="url(#p280dd08963)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p62fc16713e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p62fc16713e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26391,7 +26391,7 @@ L 535.462185 356.103529 L 535.462185 337.468235 L 512.016807 337.468235 z -" clip-path="url(#p47367981f5)" style="fill: #ffeded; opacity: 0.5; stroke: #ffeded; stroke-linejoin: miter"/> +" clip-path="url(#p69ea16b852)" style="fill: #ffeded; opacity: 0.5; stroke: #ffeded; stroke-linejoin: miter"/> @@ -26476,12 +26476,12 @@ L 533.587094 347.578742 L 533.856891 347.576238 L 534.126689 347.574762 L 534.396486 347.574277 -" clip-path="url(#p47367981f5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p69ea16b852)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p69ea16b852)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26499,7 +26499,7 @@ L 563.596639 356.103529 L 563.596639 337.468235 L 540.151261 337.468235 z -" clip-path="url(#p892801c44e)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> +" clip-path="url(#p21059a8913)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> @@ -26584,12 +26584,12 @@ L 561.721548 347.575337 L 561.991345 347.574743 L 562.261142 347.574392 L 562.53094 347.574277 -" clip-path="url(#p892801c44e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p21059a8913)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p21059a8913)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26607,7 +26607,7 @@ L 591.731092 356.103529 L 591.731092 337.468235 L 568.285714 337.468235 z -" clip-path="url(#p19460c5602)" style="fill: #ff8181; opacity: 0.5; stroke: #ff8181; stroke-linejoin: miter"/> +" clip-path="url(#p2d2ffb39fe)" style="fill: #ff8181; opacity: 0.5; stroke: #ff8181; stroke-linejoin: miter"/> @@ -26692,12 +26692,12 @@ L 589.856002 347.567215 L 590.125799 347.571176 L 590.395596 347.573511 L 590.665393 347.574277 -" clip-path="url(#p19460c5602)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d2ffb39fe)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d2ffb39fe)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26715,7 +26715,7 @@ L 619.865546 356.103529 L 619.865546 337.468235 L 596.420168 337.468235 z -" clip-path="url(#pc437812ad5)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> +" clip-path="url(#pc6d67363af)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> @@ -26800,12 +26800,12 @@ L 617.990456 347.570843 L 618.260253 347.572769 L 618.53005 347.573905 L 618.799847 347.574277 -" clip-path="url(#pc437812ad5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc6d67363af)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc6d67363af)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26823,7 +26823,7 @@ L 113.445378 378.465882 L 113.445378 359.830588 L 90 359.830588 z -" clip-path="url(#pea1b193120)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> +" clip-path="url(#pf4994b72bd)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> @@ -26908,12 +26908,12 @@ L 111.570287 369.250612 L 111.840085 369.251272 L 112.109882 369.251661 L 112.379679 369.251788 -" clip-path="url(#pea1b193120)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf4994b72bd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf4994b72bd)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26931,7 +26931,7 @@ L 141.579832 378.465882 L 141.579832 359.830588 L 118.134454 359.830588 z -" clip-path="url(#p467f68014c)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#p749f63e8d3)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -27016,12 +27016,12 @@ L 139.704741 369.249925 L 139.974538 369.25097 L 140.244336 369.251586 L 140.514133 369.251788 -" clip-path="url(#p467f68014c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p749f63e8d3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p749f63e8d3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27039,7 +27039,7 @@ L 169.714286 378.465882 L 169.714286 359.830588 L 146.268908 359.830588 z -" clip-path="url(#p8c15cc58be)" style="fill: #ff5959; opacity: 0.5; stroke: #ff5959; stroke-linejoin: miter"/> +" clip-path="url(#p0fb23e3e31)" style="fill: #ff5959; opacity: 0.5; stroke: #ff5959; stroke-linejoin: miter"/> @@ -27124,12 +27124,12 @@ L 167.839195 369.252233 L 168.108992 369.251984 L 168.378789 369.251837 L 168.648587 369.251788 -" clip-path="url(#p8c15cc58be)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0fb23e3e31)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0fb23e3e31)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27147,7 +27147,7 @@ L 197.848739 378.465882 L 197.848739 359.830588 L 174.403361 359.830588 z -" clip-path="url(#p57edcc5d5b)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> +" clip-path="url(#p89d14f7956)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> @@ -27232,12 +27232,12 @@ L 195.973649 369.249071 L 196.243446 369.250595 L 196.513243 369.251494 L 196.78304 369.251788 -" clip-path="url(#p57edcc5d5b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p89d14f7956)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p89d14f7956)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27255,7 +27255,7 @@ L 225.983193 378.465882 L 225.983193 359.830588 L 202.537815 359.830588 z -" clip-path="url(#p4ab4d99a8a)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#p3aa0912ed9)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -27340,12 +27340,12 @@ L 224.108103 369.254011 L 224.3779 369.252764 L 224.647697 369.252029 L 224.917494 369.251788 -" clip-path="url(#p4ab4d99a8a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3aa0912ed9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3aa0912ed9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27363,7 +27363,7 @@ L 254.117647 378.465882 L 254.117647 359.830588 L 230.672269 359.830588 z -" clip-path="url(#p814386dd58)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> +" clip-path="url(#pccc3defb6d)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> @@ -27448,12 +27448,12 @@ L 252.242556 369.256674 L 252.512354 369.253934 L 252.782151 369.252318 L 253.051948 369.251788 -" clip-path="url(#p814386dd58)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pccc3defb6d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pccc3defb6d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27471,7 +27471,7 @@ L 282.252101 378.465882 L 282.252101 359.830588 L 258.806723 359.830588 z -" clip-path="url(#p58f239f7b8)" style="fill: #7d7dff; opacity: 0.5; stroke: #7d7dff; stroke-linejoin: miter"/> +" clip-path="url(#pd8637aeb91)" style="fill: #7d7dff; opacity: 0.5; stroke: #7d7dff; stroke-linejoin: miter"/> @@ -27556,12 +27556,12 @@ L 280.37701 369.258876 L 280.646807 369.254901 L 280.916605 369.252557 L 281.186402 369.251788 -" clip-path="url(#p58f239f7b8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd8637aeb91)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd8637aeb91)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27579,7 +27579,7 @@ L 310.386555 378.465882 L 310.386555 359.830588 L 286.941176 359.830588 z -" clip-path="url(#pcd23277dbe)" style="fill: #0000ae; opacity: 0.5; stroke: #0000ae; stroke-linejoin: miter"/> +" clip-path="url(#p5b29a7b325)" style="fill: #0000ae; opacity: 0.5; stroke: #0000ae; stroke-linejoin: miter"/> @@ -27664,12 +27664,12 @@ L 308.511464 369.27243 L 308.781261 369.260854 L 309.051058 369.254028 L 309.320856 369.251788 -" clip-path="url(#pcd23277dbe)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5b29a7b325)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5b29a7b325)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27687,7 +27687,7 @@ L 338.521008 378.465882 L 338.521008 359.830588 L 315.07563 359.830588 z -" clip-path="url(#pc1abdd9c3a)" style="fill: #4141ff; opacity: 0.5; stroke: #4141ff; stroke-linejoin: miter"/> +" clip-path="url(#p4ff648f573)" style="fill: #4141ff; opacity: 0.5; stroke: #4141ff; stroke-linejoin: miter"/> @@ -27772,12 +27772,12 @@ L 336.645918 369.26069 L 336.915715 369.255698 L 337.185512 369.252754 L 337.455309 369.251788 -" clip-path="url(#pc1abdd9c3a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4ff648f573)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4ff648f573)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27795,7 +27795,7 @@ L 366.655462 378.465882 L 366.655462 359.830588 L 343.210084 359.830588 z -" clip-path="url(#pb9ae6b9751)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> +" clip-path="url(#pe1b8eafd94)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> @@ -27880,12 +27880,12 @@ L 364.780372 369.241203 L 365.050169 369.247139 L 365.319966 369.25064 L 365.589763 369.251788 -" clip-path="url(#pb9ae6b9751)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe1b8eafd94)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe1b8eafd94)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27903,7 +27903,7 @@ L 394.789916 378.465882 L 394.789916 359.830588 L 371.344538 359.830588 z -" clip-path="url(#p3df32830c3)" style="fill: #ff7575; opacity: 0.5; stroke: #ff7575; stroke-linejoin: miter"/> +" clip-path="url(#p45f1ab2e11)" style="fill: #ff7575; opacity: 0.5; stroke: #ff7575; stroke-linejoin: miter"/> @@ -27988,12 +27988,12 @@ L 392.914825 369.248174 L 393.184623 369.250201 L 393.45442 369.251396 L 393.724217 369.251788 -" clip-path="url(#p3df32830c3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p45f1ab2e11)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p45f1ab2e11)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28011,7 +28011,7 @@ L 422.92437 378.465882 L 422.92437 359.830588 L 399.478992 359.830588 z -" clip-path="url(#pc647761215)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> +" clip-path="url(#pce1251983f)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> @@ -28096,12 +28096,12 @@ L 421.049279 369.254431 L 421.319076 369.252949 L 421.588874 369.252075 L 421.858671 369.251788 -" clip-path="url(#pc647761215)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pce1251983f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pce1251983f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28119,7 +28119,7 @@ L 451.058824 378.465882 L 451.058824 359.830588 L 427.613445 359.830588 z -" clip-path="url(#pfa43d9b4b5)" style="fill: #ff6161; opacity: 0.5; stroke: #ff6161; stroke-linejoin: miter"/> +" clip-path="url(#p8da23a69bd)" style="fill: #ff6161; opacity: 0.5; stroke: #ff6161; stroke-linejoin: miter"/> @@ -28204,12 +28204,12 @@ L 449.183733 369.253163 L 449.45353 369.252392 L 449.723327 369.251937 L 449.993125 369.251788 -" clip-path="url(#pfa43d9b4b5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8da23a69bd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8da23a69bd)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28227,7 +28227,7 @@ L 479.193277 378.465882 L 479.193277 359.830588 L 455.747899 359.830588 z -" clip-path="url(#pb40d7f9695)" style="fill: #ff5d5d; opacity: 0.5; stroke: #ff5d5d; stroke-linejoin: miter"/> +" clip-path="url(#pb8e304de3d)" style="fill: #ff5d5d; opacity: 0.5; stroke: #ff5d5d; stroke-linejoin: miter"/> @@ -28312,12 +28312,12 @@ L 477.318187 369.25178 L 477.587984 369.251785 L 477.857781 369.251787 L 478.127578 369.251788 -" clip-path="url(#pb40d7f9695)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb8e304de3d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb8e304de3d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28335,7 +28335,7 @@ L 507.327731 378.465882 L 507.327731 359.830588 L 483.882353 359.830588 z -" clip-path="url(#pe6b14533b5)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#pbd6030649a)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -28420,12 +28420,12 @@ L 505.45264 369.24685 L 505.722438 369.249619 L 505.992235 369.251253 L 506.262032 369.251788 -" clip-path="url(#pe6b14533b5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbd6030649a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbd6030649a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28443,7 +28443,7 @@ L 535.462185 378.465882 L 535.462185 359.830588 L 512.016807 359.830588 z -" clip-path="url(#p5fb9242ed9)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> +" clip-path="url(#p409c214a63)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> @@ -28528,12 +28528,12 @@ L 533.587094 369.250883 L 533.856891 369.251391 L 534.126689 369.25169 L 534.396486 369.251788 -" clip-path="url(#p5fb9242ed9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p409c214a63)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p409c214a63)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28551,7 +28551,7 @@ L 563.596639 378.465882 L 563.596639 359.830588 L 540.151261 359.830588 z -" clip-path="url(#pc96d1f606e)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> +" clip-path="url(#p93aa5c7dfd)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> @@ -28636,12 +28636,12 @@ L 561.721548 369.255898 L 561.991345 369.253593 L 562.261142 369.252234 L 562.53094 369.251788 -" clip-path="url(#pc96d1f606e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p93aa5c7dfd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p93aa5c7dfd)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28659,7 +28659,7 @@ L 591.731092 378.465882 L 591.731092 359.830588 L 568.285714 359.830588 z -" clip-path="url(#pb7b7febb3a)" style="fill: #e1e1ff; opacity: 0.5; stroke: #e1e1ff; stroke-linejoin: miter"/> +" clip-path="url(#p98c2c4c431)" style="fill: #e1e1ff; opacity: 0.5; stroke: #e1e1ff; stroke-linejoin: miter"/> @@ -28744,12 +28744,12 @@ L 589.856002 369.254953 L 590.125799 369.253178 L 590.395596 369.252132 L 590.665393 369.251788 -" clip-path="url(#pb7b7febb3a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p98c2c4c431)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p98c2c4c431)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28767,7 +28767,7 @@ L 619.865546 378.465882 L 619.865546 359.830588 L 596.420168 359.830588 z -" clip-path="url(#p359cd30540)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p71594f7054)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -28852,12 +28852,12 @@ L 617.990456 369.25581 L 618.260253 369.253554 L 618.53005 369.252225 L 618.799847 369.251788 -" clip-path="url(#p359cd30540)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p71594f7054)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p71594f7054)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28875,7 +28875,7 @@ L 113.445378 400.828235 L 113.445378 382.192941 L 90 382.192941 z -" clip-path="url(#pe8a5435496)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> +" clip-path="url(#p040acb652d)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> @@ -28960,12 +28960,12 @@ L 111.570287 392.679561 L 111.840085 392.6747 L 112.109882 392.671833 L 112.379679 392.670893 -" clip-path="url(#pe8a5435496)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p040acb652d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p040acb652d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28983,7 +28983,7 @@ L 141.579832 400.828235 L 141.579832 382.192941 L 118.134454 382.192941 z -" clip-path="url(#p9d002f9bc2)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> +" clip-path="url(#p5c21a2aa63)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> @@ -29068,12 +29068,12 @@ L 139.704741 392.683622 L 139.974538 392.676484 L 140.244336 392.672274 L 140.514133 392.670893 -" clip-path="url(#p9d002f9bc2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5c21a2aa63)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5c21a2aa63)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29091,7 +29091,7 @@ L 169.714286 400.828235 L 169.714286 382.192941 L 146.268908 382.192941 z -" clip-path="url(#p2aceb2f531)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> +" clip-path="url(#p52c6d5b952)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> @@ -29176,12 +29176,12 @@ L 167.839195 392.690581 L 168.108992 392.67954 L 168.378789 392.673029 L 168.648587 392.670893 -" clip-path="url(#p2aceb2f531)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p52c6d5b952)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p52c6d5b952)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29199,7 +29199,7 @@ L 197.848739 400.828235 L 197.848739 382.192941 L 174.403361 382.192941 z -" clip-path="url(#pc449efac7d)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> +" clip-path="url(#pfc9bd6801c)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> @@ -29284,12 +29284,12 @@ L 195.973649 392.681864 L 196.243446 392.675711 L 196.513243 392.672083 L 196.78304 392.670893 -" clip-path="url(#pc449efac7d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfc9bd6801c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfc9bd6801c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29307,7 +29307,7 @@ L 225.983193 400.828235 L 225.983193 382.192941 L 202.537815 382.192941 z -" clip-path="url(#p0e19863c9c)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> +" clip-path="url(#p01e6375193)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> @@ -29392,12 +29392,12 @@ L 224.108103 392.685461 L 224.3779 392.677291 L 224.647697 392.672473 L 224.917494 392.670893 -" clip-path="url(#p0e19863c9c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p01e6375193)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p01e6375193)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29415,7 +29415,7 @@ L 254.117647 400.828235 L 254.117647 382.192941 L 230.672269 382.192941 z -" clip-path="url(#pc82878cfd8)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> +" clip-path="url(#pd2a3e37e62)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> @@ -29500,12 +29500,12 @@ L 252.242556 392.694649 L 252.512354 392.681327 L 252.782151 392.67347 L 253.051948 392.670893 -" clip-path="url(#pc82878cfd8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd2a3e37e62)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd2a3e37e62)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29523,7 +29523,7 @@ L 282.252101 400.828235 L 282.252101 382.192941 L 258.806723 382.192941 z -" clip-path="url(#p9b8f0e775e)" style="fill: #e1e1ff; opacity: 0.5; stroke: #e1e1ff; stroke-linejoin: miter"/> +" clip-path="url(#p0bb47c3fe0)" style="fill: #e1e1ff; opacity: 0.5; stroke: #e1e1ff; stroke-linejoin: miter"/> @@ -29608,12 +29608,12 @@ L 280.37701 392.674501 L 280.646807 392.672478 L 280.916605 392.671284 L 281.186402 392.670893 -" clip-path="url(#p9b8f0e775e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0bb47c3fe0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0bb47c3fe0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29631,7 +29631,7 @@ L 310.386555 400.828235 L 310.386555 382.192941 L 286.941176 382.192941 z -" clip-path="url(#pa78264fe3f)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> +" clip-path="url(#p90fa1296bb)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> @@ -29716,12 +29716,12 @@ L 308.511464 392.683464 L 308.781261 392.676414 L 309.051058 392.672256 L 309.320856 392.670893 -" clip-path="url(#pa78264fe3f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p90fa1296bb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p90fa1296bb)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29739,7 +29739,7 @@ L 338.521008 400.828235 L 338.521008 382.192941 L 315.07563 382.192941 z -" clip-path="url(#pa686f9b765)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> +" clip-path="url(#pf282b057c9)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> @@ -29824,12 +29824,12 @@ L 336.645918 392.685797 L 336.915715 392.677439 L 337.185512 392.67251 L 337.455309 392.670893 -" clip-path="url(#pa686f9b765)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf282b057c9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf282b057c9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29847,7 +29847,7 @@ L 366.655462 400.828235 L 366.655462 382.192941 L 343.210084 382.192941 z -" clip-path="url(#pa88befc2d8)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#pdce55bcf4b)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -29932,12 +29932,12 @@ L 364.780372 392.680705 L 365.050169 392.675202 L 365.319966 392.671957 L 365.589763 392.670893 -" clip-path="url(#pa88befc2d8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdce55bcf4b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdce55bcf4b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29955,7 +29955,7 @@ L 394.789916 400.828235 L 394.789916 382.192941 L 371.344538 382.192941 z -" clip-path="url(#p3dde28528d)" style="fill: #ffd1d1; opacity: 0.5; stroke: #ffd1d1; stroke-linejoin: miter"/> +" clip-path="url(#pb68d034a43)" style="fill: #ffd1d1; opacity: 0.5; stroke: #ffd1d1; stroke-linejoin: miter"/> @@ -30040,12 +30040,12 @@ L 392.914825 392.670642 L 393.184623 392.670783 L 393.45442 392.670866 L 393.724217 392.670893 -" clip-path="url(#p3dde28528d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb68d034a43)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb68d034a43)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30063,7 +30063,7 @@ L 422.92437 400.828235 L 422.92437 382.192941 L 399.478992 382.192941 z -" clip-path="url(#pa2d8d0a18a)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> +" clip-path="url(#pb3c2ae434a)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> @@ -30148,12 +30148,12 @@ L 421.049279 392.67871 L 421.319076 392.674326 L 421.588874 392.671741 L 421.858671 392.670893 -" clip-path="url(#pa2d8d0a18a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb3c2ae434a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb3c2ae434a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30171,7 +30171,7 @@ L 451.058824 400.828235 L 451.058824 382.192941 L 427.613445 382.192941 z -" clip-path="url(#pef419560e6)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> +" clip-path="url(#p8a22ca0d23)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> @@ -30256,12 +30256,12 @@ L 449.183733 392.658006 L 449.45353 392.665233 L 449.723327 392.669495 L 449.993125 392.670893 -" clip-path="url(#pef419560e6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8a22ca0d23)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8a22ca0d23)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30279,7 +30279,7 @@ L 479.193277 400.828235 L 479.193277 382.192941 L 455.747899 382.192941 z -" clip-path="url(#pf6900ca480)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> +" clip-path="url(#pddae8cdf9c)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> @@ -30364,12 +30364,12 @@ L 477.318187 392.694224 L 477.587984 392.68114 L 477.857781 392.673424 L 478.127578 392.670893 -" clip-path="url(#pf6900ca480)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pddae8cdf9c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pddae8cdf9c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30387,7 +30387,7 @@ L 507.327731 400.828235 L 507.327731 382.192941 L 483.882353 382.192941 z -" clip-path="url(#p14d85e6986)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p65088a56b5)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -30472,12 +30472,12 @@ L 505.45264 392.643459 L 505.722438 392.658844 L 505.992235 392.667917 L 506.262032 392.670893 -" clip-path="url(#p14d85e6986)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p65088a56b5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p65088a56b5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30495,7 +30495,7 @@ L 535.462185 400.828235 L 535.462185 382.192941 L 512.016807 382.192941 z -" clip-path="url(#p7d04ca9b3a)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> +" clip-path="url(#pd15457ddca)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> @@ -30580,12 +30580,12 @@ L 533.587094 392.679005 L 533.856891 392.674455 L 534.126689 392.671773 L 534.396486 392.670893 -" clip-path="url(#p7d04ca9b3a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd15457ddca)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd15457ddca)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30603,7 +30603,7 @@ L 563.596639 400.828235 L 563.596639 382.192941 L 540.151261 382.192941 z -" clip-path="url(#p78e2138495)" style="fill: #ffc9c9; opacity: 0.5; stroke: #ffc9c9; stroke-linejoin: miter"/> +" clip-path="url(#pb99178bb96)" style="fill: #ffc9c9; opacity: 0.5; stroke: #ffc9c9; stroke-linejoin: miter"/> @@ -30688,12 +30688,12 @@ L 561.721548 392.6683 L 561.991345 392.669754 L 562.261142 392.670612 L 562.53094 392.670893 -" clip-path="url(#p78e2138495)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb99178bb96)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb99178bb96)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30711,7 +30711,7 @@ L 591.731092 400.828235 L 591.731092 382.192941 L 568.285714 382.192941 z -" clip-path="url(#pf9fa7f1df1)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#pba7b5a1d30)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -30796,12 +30796,12 @@ L 589.856002 392.672609 L 590.125799 392.671647 L 590.395596 392.671079 L 590.665393 392.670893 -" clip-path="url(#pf9fa7f1df1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pba7b5a1d30)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pba7b5a1d30)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30819,7 +30819,7 @@ L 619.865546 400.828235 L 619.865546 382.192941 L 596.420168 382.192941 z -" clip-path="url(#pa2eee90b37)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> +" clip-path="url(#pc6616ac3f9)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> @@ -30904,12 +30904,12 @@ L 617.990456 392.667545 L 618.260253 392.669422 L 618.53005 392.67053 L 618.799847 392.670893 -" clip-path="url(#pa2eee90b37)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc6616ac3f9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc6616ac3f9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30927,7 +30927,7 @@ L 113.445378 423.190588 L 113.445378 404.555294 L 90 404.555294 z -" clip-path="url(#p00773d5013)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> +" clip-path="url(#pe480333023)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> @@ -31012,12 +31012,12 @@ L 111.570287 415.476795 L 111.840085 415.46583 L 112.109882 415.459363 L 112.379679 415.457242 -" clip-path="url(#p00773d5013)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe480333023)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe480333023)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31035,7 +31035,7 @@ L 141.579832 423.190588 L 141.579832 404.555294 L 118.134454 404.555294 z -" clip-path="url(#p6932488431)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#p44f4c595c6)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -31120,12 +31120,12 @@ L 139.704741 415.45785 L 139.974538 415.457509 L 140.244336 415.457308 L 140.514133 415.457242 -" clip-path="url(#p6932488431)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p44f4c595c6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p44f4c595c6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31143,7 +31143,7 @@ L 169.714286 423.190588 L 169.714286 404.555294 L 146.268908 404.555294 z -" clip-path="url(#pb765aa8ff6)" style="fill: #2d2dff; opacity: 0.5; stroke: #2d2dff; stroke-linejoin: miter"/> +" clip-path="url(#pb41bfb7f52)" style="fill: #2d2dff; opacity: 0.5; stroke: #2d2dff; stroke-linejoin: miter"/> @@ -31228,12 +31228,12 @@ L 167.839195 415.480716 L 168.108992 415.467552 L 168.378789 415.459789 L 168.648587 415.457242 -" clip-path="url(#pb765aa8ff6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb41bfb7f52)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb41bfb7f52)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31251,7 +31251,7 @@ L 197.848739 423.190588 L 197.848739 404.555294 L 174.403361 404.555294 z -" clip-path="url(#p8b003481cc)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> +" clip-path="url(#p3afbe78a72)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> @@ -31336,12 +31336,12 @@ L 195.973649 415.468738 L 196.243446 415.462291 L 196.513243 415.458489 L 196.78304 415.457242 -" clip-path="url(#p8b003481cc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3afbe78a72)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3afbe78a72)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31359,7 +31359,7 @@ L 225.983193 423.190588 L 225.983193 404.555294 L 202.537815 404.555294 z -" clip-path="url(#p2dd8dc84aa)" style="fill: #4949ff; opacity: 0.5; stroke: #4949ff; stroke-linejoin: miter"/> +" clip-path="url(#p3893e18072)" style="fill: #4949ff; opacity: 0.5; stroke: #4949ff; stroke-linejoin: miter"/> @@ -31444,12 +31444,12 @@ L 224.108103 415.470715 L 224.3779 415.463159 L 224.647697 415.458704 L 224.917494 415.457242 -" clip-path="url(#p2dd8dc84aa)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3893e18072)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3893e18072)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31467,7 +31467,7 @@ L 254.117647 423.190588 L 254.117647 404.555294 L 230.672269 404.555294 z -" clip-path="url(#pad544c15b9)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> +" clip-path="url(#pf0ab4a13c0)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> @@ -31552,12 +31552,12 @@ L 252.242556 415.460686 L 252.512354 415.458755 L 252.782151 415.457616 L 253.051948 415.457242 -" clip-path="url(#pad544c15b9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf0ab4a13c0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf0ab4a13c0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31575,7 +31575,7 @@ L 282.252101 423.190588 L 282.252101 404.555294 L 258.806723 404.555294 z -" clip-path="url(#pe2cb35dd3e)" style="fill: #ffc1c1; opacity: 0.5; stroke: #ffc1c1; stroke-linejoin: miter"/> +" clip-path="url(#p1263779708)" style="fill: #ffc1c1; opacity: 0.5; stroke: #ffc1c1; stroke-linejoin: miter"/> @@ -31660,12 +31660,12 @@ L 280.37701 415.450029 L 280.646807 415.454074 L 280.916605 415.45646 L 281.186402 415.457242 -" clip-path="url(#pe2cb35dd3e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1263779708)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1263779708)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31683,7 +31683,7 @@ L 310.386555 423.190588 L 310.386555 404.555294 L 286.941176 404.555294 z -" clip-path="url(#pf128e2a3e5)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> +" clip-path="url(#p80e7fada6a)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> @@ -31768,12 +31768,12 @@ L 308.511464 415.458474 L 308.781261 415.457783 L 309.051058 415.457376 L 309.320856 415.457242 -" clip-path="url(#pf128e2a3e5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p80e7fada6a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p80e7fada6a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31791,7 +31791,7 @@ L 338.521008 423.190588 L 338.521008 404.555294 L 315.07563 404.555294 z -" clip-path="url(#p0b9135aaa7)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> +" clip-path="url(#p60265c9164)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> @@ -31876,12 +31876,12 @@ L 336.645918 415.473255 L 336.915715 415.464275 L 337.185512 415.458979 L 337.455309 415.457242 -" clip-path="url(#p0b9135aaa7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p60265c9164)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p60265c9164)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31899,7 +31899,7 @@ L 366.655462 423.190588 L 366.655462 404.555294 L 343.210084 404.555294 z -" clip-path="url(#p9a1cd1fc2d)" style="fill: #a9a9ff; opacity: 0.5; stroke: #a9a9ff; stroke-linejoin: miter"/> +" clip-path="url(#pa612f05552)" style="fill: #a9a9ff; opacity: 0.5; stroke: #a9a9ff; stroke-linejoin: miter"/> @@ -31984,12 +31984,12 @@ L 364.780372 415.464478 L 365.050169 415.46042 L 365.319966 415.458027 L 365.589763 415.457242 -" clip-path="url(#p9a1cd1fc2d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa612f05552)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa612f05552)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32007,7 +32007,7 @@ L 394.789916 423.190588 L 394.789916 404.555294 L 371.344538 404.555294 z -" clip-path="url(#pf2cc81180d)" style="fill: #ffd5d5; opacity: 0.5; stroke: #ffd5d5; stroke-linejoin: miter"/> +" clip-path="url(#p3f6008249c)" style="fill: #ffd5d5; opacity: 0.5; stroke: #ffd5d5; stroke-linejoin: miter"/> @@ -32092,12 +32092,12 @@ L 392.914825 415.449228 L 393.184623 415.453723 L 393.45442 415.456373 L 393.724217 415.457242 -" clip-path="url(#pf2cc81180d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3f6008249c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3f6008249c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32115,7 +32115,7 @@ L 422.92437 423.190588 L 422.92437 404.555294 L 399.478992 404.555294 z -" clip-path="url(#p71868f6ae1)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#p2269a289e5)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -32200,12 +32200,12 @@ L 421.049279 415.46869 L 421.319076 415.46227 L 421.588874 415.458484 L 421.858671 415.457242 -" clip-path="url(#p71868f6ae1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2269a289e5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2269a289e5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32223,7 +32223,7 @@ L 451.058824 423.190588 L 451.058824 404.555294 L 427.613445 404.555294 z -" clip-path="url(#pa141e5383b)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#pa1e64b7c44)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -32308,12 +32308,12 @@ L 449.183733 415.449992 L 449.45353 415.454058 L 449.723327 415.456456 L 449.993125 415.457242 -" clip-path="url(#pa141e5383b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa1e64b7c44)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa1e64b7c44)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32331,7 +32331,7 @@ L 479.193277 423.190588 L 479.193277 404.555294 L 455.747899 404.555294 z -" clip-path="url(#pe1639db9e9)" style="fill: #ff9999; opacity: 0.5; stroke: #ff9999; stroke-linejoin: miter"/> +" clip-path="url(#pe6ba4a3ac6)" style="fill: #ff9999; opacity: 0.5; stroke: #ff9999; stroke-linejoin: miter"/> @@ -32416,12 +32416,12 @@ L 477.318187 415.457608 L 477.587984 415.457403 L 477.857781 415.457282 L 478.127578 415.457242 -" clip-path="url(#pe1639db9e9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe6ba4a3ac6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe6ba4a3ac6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32439,7 +32439,7 @@ L 507.327731 423.190588 L 507.327731 404.555294 L 483.882353 404.555294 z -" clip-path="url(#p8fcc587b12)" style="fill: #ff6565; opacity: 0.5; stroke: #ff6565; stroke-linejoin: miter"/> +" clip-path="url(#pf3eb80c03e)" style="fill: #ff6565; opacity: 0.5; stroke: #ff6565; stroke-linejoin: miter"/> @@ -32524,12 +32524,12 @@ L 505.45264 415.446837 L 505.722438 415.452672 L 505.992235 415.456113 L 506.262032 415.457242 -" clip-path="url(#p8fcc587b12)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf3eb80c03e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf3eb80c03e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32547,7 +32547,7 @@ L 535.462185 423.190588 L 535.462185 404.555294 L 512.016807 404.555294 z -" clip-path="url(#p73eda7b6b2)" style="fill: #ff6d6d; opacity: 0.5; stroke: #ff6d6d; stroke-linejoin: miter"/> +" clip-path="url(#p34f40ed1f5)" style="fill: #ff6d6d; opacity: 0.5; stroke: #ff6d6d; stroke-linejoin: miter"/> @@ -32632,12 +32632,12 @@ L 533.587094 415.454417 L 533.856891 415.456001 L 534.126689 415.456936 L 534.396486 415.457242 -" clip-path="url(#p73eda7b6b2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p34f40ed1f5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p34f40ed1f5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32655,7 +32655,7 @@ L 563.596639 423.190588 L 563.596639 404.555294 L 540.151261 404.555294 z -" clip-path="url(#p2d21e04b65)" style="fill: #ff9595; opacity: 0.5; stroke: #ff9595; stroke-linejoin: miter"/> +" clip-path="url(#p0c3f8321fe)" style="fill: #ff9595; opacity: 0.5; stroke: #ff9595; stroke-linejoin: miter"/> @@ -32740,12 +32740,12 @@ L 561.721548 415.462082 L 561.991345 415.459368 L 562.261142 415.457767 L 562.53094 415.457242 -" clip-path="url(#p2d21e04b65)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0c3f8321fe)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0c3f8321fe)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32763,7 +32763,7 @@ L 591.731092 423.190588 L 591.731092 404.555294 L 568.285714 404.555294 z -" clip-path="url(#pa7a81fbe99)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> +" clip-path="url(#p5765f3f7a6)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> @@ -32848,12 +32848,12 @@ L 589.856002 415.465855 L 590.125799 415.461025 L 590.395596 415.458177 L 590.665393 415.457242 -" clip-path="url(#pa7a81fbe99)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5765f3f7a6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5765f3f7a6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32871,7 +32871,7 @@ L 619.865546 423.190588 L 619.865546 404.555294 L 596.420168 404.555294 z -" clip-path="url(#p4b8a8ac4c6)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> +" clip-path="url(#pdae4fd27e0)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> @@ -32956,12 +32956,12 @@ L 617.990456 415.460143 L 618.260253 415.458516 L 618.53005 415.457557 L 618.799847 415.457242 -" clip-path="url(#p4b8a8ac4c6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdae4fd27e0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdae4fd27e0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32979,7 +32979,7 @@ L 113.445378 445.552941 L 113.445378 426.917647 L 90 426.917647 z -" clip-path="url(#p7894f4fdaf)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> +" clip-path="url(#p3de70c48b7)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> @@ -33064,12 +33064,12 @@ L 111.570287 439.308133 L 111.840085 439.306067 L 112.109882 439.304849 L 112.379679 439.304449 -" clip-path="url(#p7894f4fdaf)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3de70c48b7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3de70c48b7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33087,7 +33087,7 @@ L 141.579832 445.552941 L 141.579832 426.917647 L 118.134454 426.917647 z -" clip-path="url(#p124fe2c66d)" style="fill: #5d5dff; opacity: 0.5; stroke: #5d5dff; stroke-linejoin: miter"/> +" clip-path="url(#p1dd1f959c0)" style="fill: #5d5dff; opacity: 0.5; stroke: #5d5dff; stroke-linejoin: miter"/> @@ -33172,12 +33172,12 @@ L 139.704741 439.317069 L 139.974538 439.309992 L 140.244336 439.305818 L 140.514133 439.304449 -" clip-path="url(#p124fe2c66d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1dd1f959c0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1dd1f959c0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33195,7 +33195,7 @@ L 169.714286 445.552941 L 169.714286 426.917647 L 146.268908 426.917647 z -" clip-path="url(#pafca2b30fb)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> +" clip-path="url(#p3a27242fec)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> @@ -33280,12 +33280,12 @@ L 167.839195 439.313623 L 168.108992 439.308478 L 168.378789 439.305444 L 168.648587 439.304449 -" clip-path="url(#pafca2b30fb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3a27242fec)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3a27242fec)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33303,7 +33303,7 @@ L 197.848739 445.552941 L 197.848739 426.917647 L 174.403361 426.917647 z -" clip-path="url(#p6835d8db5f)" style="fill: #5d5dff; opacity: 0.5; stroke: #5d5dff; stroke-linejoin: miter"/> +" clip-path="url(#pc9cb119b7c)" style="fill: #5d5dff; opacity: 0.5; stroke: #5d5dff; stroke-linejoin: miter"/> @@ -33388,12 +33388,12 @@ L 195.973649 439.315047 L 196.243446 439.309103 L 196.513243 439.305599 L 196.78304 439.304449 -" clip-path="url(#p6835d8db5f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc9cb119b7c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc9cb119b7c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33411,7 +33411,7 @@ L 225.983193 445.552941 L 225.983193 426.917647 L 202.537815 426.917647 z -" clip-path="url(#p801f51ade8)" style="fill: #1919ff; opacity: 0.5; stroke: #1919ff; stroke-linejoin: miter"/> +" clip-path="url(#pdd26ef3528)" style="fill: #1919ff; opacity: 0.5; stroke: #1919ff; stroke-linejoin: miter"/> @@ -33496,12 +33496,12 @@ L 224.108103 439.314875 L 224.3779 439.309028 L 224.647697 439.30558 L 224.917494 439.304449 -" clip-path="url(#p801f51ade8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdd26ef3528)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdd26ef3528)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33519,7 +33519,7 @@ L 254.117647 445.552941 L 254.117647 426.917647 L 230.672269 426.917647 z -" clip-path="url(#paaf08853b8)" style="fill: #4545ff; opacity: 0.5; stroke: #4545ff; stroke-linejoin: miter"/> +" clip-path="url(#p9fd7a2e406)" style="fill: #4545ff; opacity: 0.5; stroke: #4545ff; stroke-linejoin: miter"/> @@ -33604,12 +33604,12 @@ L 252.242556 439.317818 L 252.512354 439.31032 L 252.782151 439.305899 L 253.051948 439.304449 -" clip-path="url(#paaf08853b8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9fd7a2e406)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9fd7a2e406)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33627,7 +33627,7 @@ L 282.252101 445.552941 L 282.252101 426.917647 L 258.806723 426.917647 z -" clip-path="url(#pe88504a6d6)" style="fill: #4949ff; opacity: 0.5; stroke: #4949ff; stroke-linejoin: miter"/> +" clip-path="url(#pb01e2149f5)" style="fill: #4949ff; opacity: 0.5; stroke: #4949ff; stroke-linejoin: miter"/> @@ -33712,12 +33712,12 @@ L 280.37701 439.314713 L 280.646807 439.308957 L 280.916605 439.305562 L 281.186402 439.304449 -" clip-path="url(#pe88504a6d6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb01e2149f5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb01e2149f5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33735,7 +33735,7 @@ L 310.386555 445.552941 L 310.386555 426.917647 L 286.941176 426.917647 z -" clip-path="url(#pcc562eef38)" style="fill: #1111ff; opacity: 0.5; stroke: #1111ff; stroke-linejoin: miter"/> +" clip-path="url(#pf0a2ba9647)" style="fill: #1111ff; opacity: 0.5; stroke: #1111ff; stroke-linejoin: miter"/> @@ -33820,12 +33820,12 @@ L 308.511464 439.316418 L 308.781261 439.309706 L 309.051058 439.305747 L 309.320856 439.304449 -" clip-path="url(#pcc562eef38)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf0a2ba9647)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf0a2ba9647)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33843,7 +33843,7 @@ L 338.521008 445.552941 L 338.521008 426.917647 L 315.07563 426.917647 z -" clip-path="url(#p990b97f351)" style="fill: #7979ff; opacity: 0.5; stroke: #7979ff; stroke-linejoin: miter"/> +" clip-path="url(#p8bf27a509a)" style="fill: #7979ff; opacity: 0.5; stroke: #7979ff; stroke-linejoin: miter"/> @@ -33928,12 +33928,12 @@ L 336.645918 439.311237 L 336.915715 439.30743 L 337.185512 439.305185 L 337.455309 439.304449 -" clip-path="url(#p990b97f351)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8bf27a509a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8bf27a509a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33951,7 +33951,7 @@ L 366.655462 445.552941 L 366.655462 426.917647 L 343.210084 426.917647 z -" clip-path="url(#p7fabbb1705)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> +" clip-path="url(#p47e5ef91c4)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> @@ -34036,12 +34036,12 @@ L 364.780372 439.304844 L 365.050169 439.304622 L 365.319966 439.304492 L 365.589763 439.304449 -" clip-path="url(#p7fabbb1705)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p47e5ef91c4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p47e5ef91c4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34059,7 +34059,7 @@ L 394.789916 445.552941 L 394.789916 426.917647 L 371.344538 426.917647 z -" clip-path="url(#p2cb81485e1)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> +" clip-path="url(#p9bf9baac17)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> @@ -34144,12 +34144,12 @@ L 392.914825 439.295674 L 393.184623 439.300595 L 393.45442 439.303497 L 393.724217 439.304449 -" clip-path="url(#p2cb81485e1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9bf9baac17)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9bf9baac17)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34167,7 +34167,7 @@ L 422.92437 445.552941 L 422.92437 426.917647 L 399.478992 426.917647 z -" clip-path="url(#p9180763706)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> +" clip-path="url(#pc345d8498e)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> @@ -34252,12 +34252,12 @@ L 421.049279 439.313554 L 421.319076 439.308448 L 421.588874 439.305437 L 421.858671 439.304449 -" clip-path="url(#p9180763706)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc345d8498e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc345d8498e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34275,7 +34275,7 @@ L 451.058824 445.552941 L 451.058824 426.917647 L 427.613445 426.917647 z -" clip-path="url(#p7de2280bae)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> +" clip-path="url(#p06aed6c63d)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> @@ -34360,12 +34360,12 @@ L 449.183733 439.296166 L 449.45353 439.300811 L 449.723327 439.30355 L 449.993125 439.304449 -" clip-path="url(#p7de2280bae)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p06aed6c63d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p06aed6c63d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34383,7 +34383,7 @@ L 479.193277 445.552941 L 479.193277 426.917647 L 455.747899 426.917647 z -" clip-path="url(#p18baf423d5)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p6cd28145cb)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -34468,12 +34468,12 @@ L 477.318187 439.315477 L 477.587984 439.309292 L 477.857781 439.305645 L 478.127578 439.304449 -" clip-path="url(#p18baf423d5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6cd28145cb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6cd28145cb)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34491,7 +34491,7 @@ L 507.327731 445.552941 L 507.327731 426.917647 L 483.882353 426.917647 z -" clip-path="url(#pf53276bd6e)" style="fill: #ffd5d5; opacity: 0.5; stroke: #ffd5d5; stroke-linejoin: miter"/> +" clip-path="url(#p6684d3259d)" style="fill: #ffd5d5; opacity: 0.5; stroke: #ffd5d5; stroke-linejoin: miter"/> @@ -34576,12 +34576,12 @@ L 505.45264 439.301718 L 505.722438 439.303249 L 505.992235 439.304153 L 506.262032 439.304449 -" clip-path="url(#pf53276bd6e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6684d3259d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6684d3259d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34599,7 +34599,7 @@ L 535.462185 445.552941 L 535.462185 426.917647 L 512.016807 426.917647 z -" clip-path="url(#pc52348655d)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#pd9ce16e0d9)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -34684,12 +34684,12 @@ L 533.587094 439.310185 L 533.856891 439.306968 L 534.126689 439.305071 L 534.396486 439.304449 -" clip-path="url(#pc52348655d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd9ce16e0d9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd9ce16e0d9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34707,7 +34707,7 @@ L 563.596639 445.552941 L 563.596639 426.917647 L 540.151261 426.917647 z -" clip-path="url(#p91cda88771)" style="fill: #ff7575; opacity: 0.5; stroke: #ff7575; stroke-linejoin: miter"/> +" clip-path="url(#pfb20f86966)" style="fill: #ff7575; opacity: 0.5; stroke: #ff7575; stroke-linejoin: miter"/> @@ -34792,12 +34792,12 @@ L 561.721548 439.299768 L 561.991345 439.302393 L 562.261142 439.303941 L 562.53094 439.304449 -" clip-path="url(#p91cda88771)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfb20f86966)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfb20f86966)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34815,7 +34815,7 @@ L 591.731092 445.552941 L 591.731092 426.917647 L 568.285714 426.917647 z -" clip-path="url(#pe70ea370f6)" style="fill: #ff6565; opacity: 0.5; stroke: #ff6565; stroke-linejoin: miter"/> +" clip-path="url(#p0cfdf8227c)" style="fill: #ff6565; opacity: 0.5; stroke: #ff6565; stroke-linejoin: miter"/> @@ -34900,12 +34900,12 @@ L 589.856002 439.291944 L 590.125799 439.298957 L 590.395596 439.303092 L 590.665393 439.304449 -" clip-path="url(#pe70ea370f6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0cfdf8227c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0cfdf8227c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34923,7 +34923,7 @@ L 619.865546 445.552941 L 619.865546 426.917647 L 596.420168 426.917647 z -" clip-path="url(#p0ece9af40b)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#pf8c4036ed5)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -35008,12 +35008,12 @@ L 617.990456 439.296575 L 618.260253 439.300991 L 618.53005 439.303595 L 618.799847 439.304449 -" clip-path="url(#p0ece9af40b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf8c4036ed5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf8c4036ed5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35031,7 +35031,7 @@ L 113.445378 467.915294 L 113.445378 449.28 L 90 449.28 z -" clip-path="url(#p1173737966)" style="fill: #7d7dff; opacity: 0.5; stroke: #7d7dff; stroke-linejoin: miter"/> +" clip-path="url(#pad45e0feef)" style="fill: #7d7dff; opacity: 0.5; stroke: #7d7dff; stroke-linejoin: miter"/> @@ -35116,12 +35116,12 @@ L 111.570287 458.537197 L 111.840085 458.530534 L 112.109882 458.526604 L 112.379679 458.525316 -" clip-path="url(#p1173737966)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pad45e0feef)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pad45e0feef)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35139,7 +35139,7 @@ L 141.579832 467.915294 L 141.579832 449.28 L 118.134454 449.28 z -" clip-path="url(#p1bba6ab641)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#p6f2af10475)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -35224,12 +35224,12 @@ L 139.704741 458.533721 L 139.974538 458.529007 L 140.244336 458.526227 L 140.514133 458.525316 -" clip-path="url(#p1bba6ab641)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6f2af10475)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6f2af10475)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35247,7 +35247,7 @@ L 169.714286 467.915294 L 169.714286 449.28 L 146.268908 449.28 z -" clip-path="url(#pb167be17c7)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> +" clip-path="url(#p2accaad9db)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> @@ -35332,12 +35332,12 @@ L 167.839195 458.544241 L 168.108992 458.533628 L 168.378789 458.527369 L 168.648587 458.525316 -" clip-path="url(#pb167be17c7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2accaad9db)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2accaad9db)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35355,7 +35355,7 @@ L 197.848739 467.915294 L 197.848739 449.28 L 174.403361 449.28 z -" clip-path="url(#p3c9417c6c3)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p397dc7ec51)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -35440,12 +35440,12 @@ L 195.973649 458.529259 L 196.243446 458.527048 L 196.513243 458.525743 L 196.78304 458.525316 -" clip-path="url(#p3c9417c6c3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p397dc7ec51)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p397dc7ec51)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35463,7 +35463,7 @@ L 225.983193 467.915294 L 225.983193 449.28 L 202.537815 449.28 z -" clip-path="url(#p13e7cdd971)" style="fill: #6161ff; opacity: 0.5; stroke: #6161ff; stroke-linejoin: miter"/> +" clip-path="url(#pda0b410ff0)" style="fill: #6161ff; opacity: 0.5; stroke: #6161ff; stroke-linejoin: miter"/> @@ -35548,12 +35548,12 @@ L 224.108103 458.544783 L 224.3779 458.533866 L 224.647697 458.527427 L 224.917494 458.525316 -" clip-path="url(#p13e7cdd971)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pda0b410ff0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pda0b410ff0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35571,7 +35571,7 @@ L 254.117647 467.915294 L 254.117647 449.28 L 230.672269 449.28 z -" clip-path="url(#pfabc9ccfd4)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> +" clip-path="url(#p0c0c443c79)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> @@ -35656,12 +35656,12 @@ L 252.242556 458.544207 L 252.512354 458.533612 L 252.782151 458.527365 L 253.051948 458.525316 -" clip-path="url(#pfabc9ccfd4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0c0c443c79)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0c0c443c79)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35679,7 +35679,7 @@ L 282.252101 467.915294 L 282.252101 449.28 L 258.806723 449.28 z -" clip-path="url(#pc0b37cadb5)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> +" clip-path="url(#p07908e3a39)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> @@ -35764,12 +35764,12 @@ L 280.37701 458.540776 L 280.646807 458.532106 L 280.916605 458.526993 L 281.186402 458.525316 -" clip-path="url(#pc0b37cadb5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p07908e3a39)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p07908e3a39)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35787,7 +35787,7 @@ L 310.386555 467.915294 L 310.386555 449.28 L 286.941176 449.28 z -" clip-path="url(#p66651fc234)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> +" clip-path="url(#pe215291557)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> @@ -35872,12 +35872,12 @@ L 308.511464 458.543034 L 308.781261 458.533098 L 309.051058 458.527238 L 309.320856 458.525316 -" clip-path="url(#p66651fc234)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe215291557)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe215291557)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35895,7 +35895,7 @@ L 338.521008 467.915294 L 338.521008 449.28 L 315.07563 449.28 z -" clip-path="url(#pb9dfca8be6)" style="fill: #7171ff; opacity: 0.5; stroke: #7171ff; stroke-linejoin: miter"/> +" clip-path="url(#pf56c863331)" style="fill: #7171ff; opacity: 0.5; stroke: #7171ff; stroke-linejoin: miter"/> @@ -35980,12 +35980,12 @@ L 336.645918 458.551909 L 336.915715 458.536996 L 337.185512 458.5282 L 337.455309 458.525316 -" clip-path="url(#pb9dfca8be6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf56c863331)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf56c863331)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36003,7 +36003,7 @@ L 366.655462 467.915294 L 366.655462 449.28 L 343.210084 449.28 z -" clip-path="url(#peec4ab2a09)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> +" clip-path="url(#p77cd95097f)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> @@ -36088,12 +36088,12 @@ L 364.780372 458.545604 L 365.050169 458.534226 L 365.319966 458.527516 L 365.589763 458.525316 -" clip-path="url(#peec4ab2a09)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p77cd95097f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p77cd95097f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36111,7 +36111,7 @@ L 394.789916 467.915294 L 394.789916 449.28 L 371.344538 449.28 z -" clip-path="url(#p628c8ba24f)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> +" clip-path="url(#pc42a660ef4)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> @@ -36196,12 +36196,12 @@ L 392.914825 458.533235 L 393.184623 458.528794 L 393.45442 458.526175 L 393.724217 458.525316 -" clip-path="url(#p628c8ba24f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc42a660ef4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc42a660ef4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36219,7 +36219,7 @@ L 422.92437 467.915294 L 422.92437 449.28 L 399.478992 449.28 z -" clip-path="url(#p129a6fed0f)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> +" clip-path="url(#pa7e354b83a)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> @@ -36304,12 +36304,12 @@ L 421.049279 458.530407 L 421.319076 458.527552 L 421.588874 458.525868 L 421.858671 458.525316 -" clip-path="url(#p129a6fed0f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa7e354b83a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa7e354b83a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36327,7 +36327,7 @@ L 451.058824 467.915294 L 451.058824 449.28 L 427.613445 449.28 z -" clip-path="url(#pbcb88a9d17)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> +" clip-path="url(#p8ec0e7132d)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> @@ -36412,12 +36412,12 @@ L 449.183733 458.516273 L 449.45353 458.521344 L 449.723327 458.524335 L 449.993125 458.525316 -" clip-path="url(#pbcb88a9d17)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ec0e7132d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ec0e7132d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36435,7 +36435,7 @@ L 479.193277 467.915294 L 479.193277 449.28 L 455.747899 449.28 z -" clip-path="url(#p523282c41a)" style="fill: #ffeded; opacity: 0.5; stroke: #ffeded; stroke-linejoin: miter"/> +" clip-path="url(#p1564a41dbd)" style="fill: #ffeded; opacity: 0.5; stroke: #ffeded; stroke-linejoin: miter"/> @@ -36520,12 +36520,12 @@ L 477.318187 458.520706 L 477.587984 458.523291 L 477.857781 458.524815 L 478.127578 458.525316 -" clip-path="url(#p523282c41a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1564a41dbd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1564a41dbd)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36543,7 +36543,7 @@ L 507.327731 467.915294 L 507.327731 449.28 L 483.882353 449.28 z -" clip-path="url(#pc58581f156)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> +" clip-path="url(#pf40080e462)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> @@ -36628,12 +36628,12 @@ L 505.45264 458.515312 L 505.722438 458.520922 L 505.992235 458.52423 L 506.262032 458.525316 -" clip-path="url(#pc58581f156)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf40080e462)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf40080e462)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36651,7 +36651,7 @@ L 535.462185 467.915294 L 535.462185 449.28 L 512.016807 449.28 z -" clip-path="url(#pc5f3f7399c)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> +" clip-path="url(#p03d6232c99)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> @@ -36736,12 +36736,12 @@ L 533.587094 458.534952 L 533.856891 458.529548 L 534.126689 458.526361 L 534.396486 458.525316 -" clip-path="url(#pc5f3f7399c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p03d6232c99)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p03d6232c99)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36759,7 +36759,7 @@ L 563.596639 467.915294 L 563.596639 449.28 L 540.151261 449.28 z -" clip-path="url(#pef4e2d1aaf)" style="fill: #ffeded; opacity: 0.5; stroke: #ffeded; stroke-linejoin: miter"/> +" clip-path="url(#p1897ee2d27)" style="fill: #ffeded; opacity: 0.5; stroke: #ffeded; stroke-linejoin: miter"/> @@ -36844,12 +36844,12 @@ L 561.721548 458.523184 L 561.991345 458.524379 L 562.261142 458.525084 L 562.53094 458.525316 -" clip-path="url(#pef4e2d1aaf)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1897ee2d27)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1897ee2d27)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36867,7 +36867,7 @@ L 591.731092 467.915294 L 591.731092 449.28 L 568.285714 449.28 z -" clip-path="url(#pda275786ba)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#peb40f8c2ec)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -36952,12 +36952,12 @@ L 589.856002 458.500033 L 590.125799 458.514211 L 590.395596 458.522573 L 590.665393 458.525316 -" clip-path="url(#pda275786ba)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#peb40f8c2ec)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#peb40f8c2ec)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36975,7 +36975,7 @@ L 619.865546 467.915294 L 619.865546 449.28 L 596.420168 449.28 z -" clip-path="url(#p3554fcaf14)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> +" clip-path="url(#p0aab5aa473)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> @@ -37060,12 +37060,12 @@ L 617.990456 458.508604 L 618.260253 458.517976 L 618.53005 458.523503 L 618.799847 458.525316 -" clip-path="url(#p3554fcaf14)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0aab5aa473)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0aab5aa473)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37083,7 +37083,7 @@ L 113.445378 490.277647 L 113.445378 471.642353 L 90 471.642353 z -" clip-path="url(#pe8e28b5799)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> +" clip-path="url(#pae31175321)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> @@ -37168,12 +37168,12 @@ L 111.570287 481.165739 L 111.840085 481.163532 L 112.109882 481.162231 L 112.379679 481.161804 -" clip-path="url(#pe8e28b5799)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pae31175321)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pae31175321)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37191,7 +37191,7 @@ L 141.579832 490.277647 L 141.579832 471.642353 L 118.134454 471.642353 z -" clip-path="url(#p130131b52e)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> +" clip-path="url(#pc41c6b7ba7)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> @@ -37276,12 +37276,12 @@ L 139.704741 481.164234 L 139.974538 481.162871 L 140.244336 481.162068 L 140.514133 481.161804 -" clip-path="url(#p130131b52e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc41c6b7ba7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc41c6b7ba7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37299,7 +37299,7 @@ L 169.714286 490.277647 L 169.714286 471.642353 L 146.268908 471.642353 z -" clip-path="url(#p9510348744)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> +" clip-path="url(#p29160fd78a)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> @@ -37384,12 +37384,12 @@ L 167.839195 481.165936 L 168.108992 481.163619 L 168.378789 481.162252 L 168.648587 481.161804 -" clip-path="url(#p9510348744)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p29160fd78a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p29160fd78a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37407,7 +37407,7 @@ L 197.848739 490.277647 L 197.848739 471.642353 L 174.403361 471.642353 z -" clip-path="url(#p65e4a3752e)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#pdf66c5d7d5)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -37492,12 +37492,12 @@ L 195.973649 481.1597 L 196.243446 481.16088 L 196.513243 481.161576 L 196.78304 481.161804 -" clip-path="url(#p65e4a3752e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdf66c5d7d5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdf66c5d7d5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37515,7 +37515,7 @@ L 225.983193 490.277647 L 225.983193 471.642353 L 202.537815 471.642353 z -" clip-path="url(#pb8d03303d2)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> +" clip-path="url(#p9752e93e8b)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> @@ -37600,12 +37600,12 @@ L 224.108103 481.172929 L 224.3779 481.16669 L 224.647697 481.163011 L 224.917494 481.161804 -" clip-path="url(#pb8d03303d2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9752e93e8b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9752e93e8b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37623,7 +37623,7 @@ L 254.117647 490.277647 L 254.117647 471.642353 L 230.672269 471.642353 z -" clip-path="url(#p3b86b58cf8)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> +" clip-path="url(#pf47c27d5ac)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> @@ -37708,12 +37708,12 @@ L 252.242556 481.170119 L 252.512354 481.165456 L 252.782151 481.162706 L 253.051948 481.161804 -" clip-path="url(#p3b86b58cf8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf47c27d5ac)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf47c27d5ac)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37731,7 +37731,7 @@ L 282.252101 490.277647 L 282.252101 471.642353 L 258.806723 471.642353 z -" clip-path="url(#pf473a07ce3)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#pa04dc76dd1)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -37816,12 +37816,12 @@ L 280.37701 481.173222 L 280.646807 481.166819 L 280.916605 481.163043 L 281.186402 481.161804 -" clip-path="url(#pf473a07ce3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa04dc76dd1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa04dc76dd1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37839,7 +37839,7 @@ L 310.386555 490.277647 L 310.386555 471.642353 L 286.941176 471.642353 z -" clip-path="url(#p74e7bad1d4)" style="fill: #a9a9ff; opacity: 0.5; stroke: #a9a9ff; stroke-linejoin: miter"/> +" clip-path="url(#p4f0022747c)" style="fill: #a9a9ff; opacity: 0.5; stroke: #a9a9ff; stroke-linejoin: miter"/> @@ -37924,12 +37924,12 @@ L 308.511464 481.176262 L 308.781261 481.168154 L 309.051058 481.163373 L 309.320856 481.161804 -" clip-path="url(#p74e7bad1d4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4f0022747c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4f0022747c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37947,7 +37947,7 @@ L 338.521008 490.277647 L 338.521008 471.642353 L 315.07563 471.642353 z -" clip-path="url(#p95bbdd15d0)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> +" clip-path="url(#pca9d192d86)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> @@ -38032,12 +38032,12 @@ L 336.645918 481.180929 L 336.915715 481.170204 L 337.185512 481.163879 L 337.455309 481.161804 -" clip-path="url(#p95bbdd15d0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pca9d192d86)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pca9d192d86)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38055,7 +38055,7 @@ L 366.655462 490.277647 L 366.655462 471.642353 L 343.210084 471.642353 z -" clip-path="url(#p275c92d16a)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> +" clip-path="url(#pd830fa49e2)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> @@ -38140,12 +38140,12 @@ L 364.780372 481.178016 L 365.050169 481.168924 L 365.319966 481.163563 L 365.589763 481.161804 -" clip-path="url(#p275c92d16a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd830fa49e2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd830fa49e2)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38163,7 +38163,7 @@ L 394.789916 490.277647 L 394.789916 471.642353 L 371.344538 471.642353 z -" clip-path="url(#p333bc8821d)" style="fill: #5959ff; opacity: 0.5; stroke: #5959ff; stroke-linejoin: miter"/> +" clip-path="url(#p4f6b64c505)" style="fill: #5959ff; opacity: 0.5; stroke: #5959ff; stroke-linejoin: miter"/> @@ -38248,12 +38248,12 @@ L 392.914825 481.18662 L 393.184623 481.172703 L 393.45442 481.164496 L 393.724217 481.161804 -" clip-path="url(#p333bc8821d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4f6b64c505)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4f6b64c505)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38271,7 +38271,7 @@ L 422.92437 490.277647 L 422.92437 471.642353 L 399.478992 471.642353 z -" clip-path="url(#p5b054da1e9)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> +" clip-path="url(#p91102d22a9)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> @@ -38356,12 +38356,12 @@ L 421.049279 481.167207 L 421.319076 481.164177 L 421.588874 481.16239 L 421.858671 481.161804 -" clip-path="url(#p5b054da1e9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p91102d22a9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p91102d22a9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38379,7 +38379,7 @@ L 451.058824 490.277647 L 451.058824 471.642353 L 427.613445 471.642353 z -" clip-path="url(#pfd8759cce8)" style="fill: #ff7575; opacity: 0.5; stroke: #ff7575; stroke-linejoin: miter"/> +" clip-path="url(#p955872868e)" style="fill: #ff7575; opacity: 0.5; stroke: #ff7575; stroke-linejoin: miter"/> @@ -38464,12 +38464,12 @@ L 449.183733 481.145069 L 449.45353 481.154454 L 449.723327 481.159989 L 449.993125 481.161804 -" clip-path="url(#pfd8759cce8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p955872868e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p955872868e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38487,7 +38487,7 @@ L 479.193277 490.277647 L 479.193277 471.642353 L 455.747899 471.642353 z -" clip-path="url(#pe98d4e165a)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> +" clip-path="url(#p48d5067782)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> @@ -38572,12 +38572,12 @@ L 477.318187 481.167085 L 477.587984 481.164123 L 477.857781 481.162377 L 478.127578 481.161804 -" clip-path="url(#pe98d4e165a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p48d5067782)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p48d5067782)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38595,7 +38595,7 @@ L 507.327731 490.277647 L 507.327731 471.642353 L 483.882353 471.642353 z -" clip-path="url(#pd160d28477)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> +" clip-path="url(#p6aaebb25f1)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> @@ -38680,12 +38680,12 @@ L 505.45264 481.174124 L 505.722438 481.167215 L 505.992235 481.163141 L 506.262032 481.161804 -" clip-path="url(#pd160d28477)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6aaebb25f1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6aaebb25f1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38703,7 +38703,7 @@ L 535.462185 490.277647 L 535.462185 471.642353 L 512.016807 471.642353 z -" clip-path="url(#p788accdf43)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#p3f9661e63a)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -38788,12 +38788,12 @@ L 533.587094 481.163328 L 533.856891 481.162473 L 534.126689 481.161969 L 534.396486 481.161804 -" clip-path="url(#p788accdf43)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3f9661e63a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3f9661e63a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38811,7 +38811,7 @@ L 563.596639 490.277647 L 563.596639 471.642353 L 540.151261 471.642353 z -" clip-path="url(#p3848a5951a)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#p3fd435794b)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -38896,12 +38896,12 @@ L 561.721548 481.152977 L 561.991345 481.157927 L 562.261142 481.160847 L 562.53094 481.161804 -" clip-path="url(#p3848a5951a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3fd435794b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3fd435794b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38919,7 +38919,7 @@ L 591.731092 490.277647 L 591.731092 471.642353 L 568.285714 471.642353 z -" clip-path="url(#peb85d72e81)" style="fill: #ff6969; opacity: 0.5; stroke: #ff6969; stroke-linejoin: miter"/> +" clip-path="url(#pa4017c7e65)" style="fill: #ff6969; opacity: 0.5; stroke: #ff6969; stroke-linejoin: miter"/> @@ -39004,12 +39004,12 @@ L 589.856002 481.149053 L 590.125799 481.156204 L 590.395596 481.160421 L 590.665393 481.161804 -" clip-path="url(#peb85d72e81)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa4017c7e65)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa4017c7e65)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -39027,7 +39027,7 @@ L 619.865546 490.277647 L 619.865546 471.642353 L 596.420168 471.642353 z -" clip-path="url(#p86aee7db2a)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p508d5407d7)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -39112,12 +39112,12 @@ L 617.990456 481.143418 L 618.260253 481.153729 L 618.53005 481.15981 L 618.799847 481.161804 -" clip-path="url(#p86aee7db2a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p508d5407d7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p508d5407d7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -39173,7 +39173,7 @@ z - - - + + @@ -39368,7 +39368,7 @@ z - - - + + @@ -39563,7 +39563,7 @@ z - - - + + @@ -39758,7 +39758,7 @@ z - - - + + @@ -39953,7 +39953,7 @@ z - - - + + @@ -40148,7 +40148,7 @@ z - - - + + @@ -40343,7 +40343,7 @@ z - - - + + @@ -40538,7 +40538,7 @@ z - - - + + @@ -40733,7 +40733,7 @@ z - - - + + @@ -40928,7 +40928,7 @@ z - - - + + @@ -41123,7 +41123,7 @@ z - - - + + @@ -41318,7 +41318,7 @@ z - - - + + @@ -41513,7 +41513,7 @@ z - - - + + @@ -41708,7 +41708,7 @@ z - - - + + @@ -41903,7 +41903,7 @@ z - - - + + @@ -42098,7 +42098,7 @@ z - - - + + @@ -42293,7 +42293,7 @@ z - - - + + @@ -42488,7 +42488,7 @@ z - - - + + @@ -42683,7 +42683,7 @@ z - - - + + @@ -42878,7 +42878,7 @@ z - - - + + @@ -43073,7 +43073,7 @@ z - - - + + @@ -43268,7 +43268,7 @@ z - - - + + @@ -43463,7 +43463,7 @@ z - - - + + @@ -43658,7 +43658,7 @@ z - - - + + @@ -43853,7 +43853,7 @@ z - - - + + @@ -44048,7 +44048,7 @@ z - - - + + @@ -44243,7 +44243,7 @@ z - - - + + @@ -44438,7 +44438,7 @@ z - - - + + @@ -44725,7 +44725,7 @@ z - - - + + @@ -44920,7 +44920,7 @@ z - - - + + @@ -45115,7 +45115,7 @@ z - - - + + @@ -45310,7 +45310,7 @@ z - - - + + @@ -45505,7 +45505,7 @@ z - - - + + @@ -45700,7 +45700,7 @@ z - - - + + @@ -45895,7 +45895,7 @@ z - - - + + @@ -46090,7 +46090,7 @@ z - - - + + @@ -46285,7 +46285,7 @@ z - - - + + @@ -46480,7 +46480,7 @@ z - - - + + @@ -46783,1090 +46783,1090 @@ z - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - 2024-11-21T16:50:14.287475 + 2024-11-21T17:17:54.612554 image/svg+xml @@ -37,20 +37,20 @@ L 47.783588 53.206588 z " style="fill: #ffffff"/> - + +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" id="imagef85f7c7dac" transform="scale(1 -1) translate(0 -219.6)" x="47.783588" y="-52.929412" width="219.6" height="219.6"/> - - + @@ -86,7 +86,7 @@ z - + @@ -125,7 +125,7 @@ z - + @@ -159,7 +159,7 @@ z - + @@ -204,7 +204,7 @@ z - + @@ -258,7 +258,7 @@ z - + @@ -290,12 +290,12 @@ z - - + @@ -308,7 +308,7 @@ L -3.5 0 - + @@ -321,7 +321,7 @@ L -3.5 0 - + @@ -334,7 +334,7 @@ L -3.5 0 - + @@ -347,7 +347,7 @@ L -3.5 0 - + @@ -360,7 +360,7 @@ L -3.5 0 - + @@ -632,15 +632,15 @@ L 332.183588 53.206588 z " style="fill: #ffffff"/> - + +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" id="image34380013f2" transform="scale(1 -1) translate(0 -219.6)" x="332.183588" y="-52.929412" width="219.6" height="219.6"/> - + @@ -653,7 +653,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -666,7 +666,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -679,7 +679,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -692,7 +692,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -705,7 +705,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -721,7 +721,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -734,7 +734,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -747,7 +747,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -760,7 +760,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -773,7 +773,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -786,7 +786,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -1019,15 +1019,15 @@ L 616.583588 53.206588 z " style="fill: #ffffff"/> - + +iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3TtBUZBhc6MOhCBAWZlRvRvejGja7mFrwQmQtx64hbqQtHFB2QgYrVjrV/M00mbXJyvIr3wAOfzw085Jzkm9/uXfzo3ofrDFtcvz49kSR5/Z13xjce//x8fCNJPv7go/GNT98ejW98+LtfjG8kyc2/7YxvnLx/Ob6RJD/7/oPxjadvboxvJMnvH3xrfGNrfAFgkIgB1UQMqCZiQDURA6qJGFBNxIBqIgZUEzGgmogB1UQMqCZiQDURA6qJGFBNxIBqIgZUEzGgmogB1UQMqCZiQDURA6qJGFBNxIBqIgZUWy525o+OZj1+nzdJsntyMb5x+XRvfCNJ/nA+fwj4vxe3xze2T5bjG0ly+Gg1vnH9+fb4RpL85vEH4xuLq/GJJMn9h/NDXmJANREDqokYUE3EgGoiBlQTMaCaiAHVRAyoJmJANREDqokYUE3EgGoiBlQTMaCaiAHVRAyoJmJANREDqokYUE3EgGoiBlQTMaCaiAHVRAyoJmJAtWV25y+Ar8/fjG8kyc6T1+Mbd/58d3wjSX51+JP5kcX8xK1/bmAkyd6Tt+Mbhyfn4xtJcvTX+bfF4mL+YnqSbL0+m98YXwAYJGJANREDqokYUE3EgGoiBlQTMaCaiAHVRAyoJmJANREDqokYUE3EgGoiBlQTMaCaiAHVRAyoJmJANREDqokYUE3EgGoiBlQTMaCaiAHVllldza9crec3kixOTsc3jv+yN76RJMsv98c33tzawJHWDX33L9+7Pr6x92z+0HSSHHx2Mr6xePR4fCNJLk/mD1p7iQHVRAyoJmJANREDqokYUE3EgGoiBlQTMaCaiAHVRAyoJmJANREDqokYUE3EgGoiBlQTMaCaiAHVRAyoJmJANREDqokYUE3EgGoiBlQTMaCaiAHVllnPX2heHGzmavZ6f/4K9GK1mYvW+08uxzcur81ftH7+7Q1cmE/ylfeejm/8+9nN8Y0kOf74aHzj3hen4xtJklfz18y9xIBqIgZUEzGgmogB1UQMqCZiQDURA6qJGFBNxIBqIgZUEzGgmogB1UQMqCZiQDURA6qJGFBNxIBqIgZUEzGgmogB1UQMqCZiQDURA6qJGFBtub51Y3zkzVcPxzeS5Oz+/DHYxWZuwWbnbH5oEz/L+sZqfiTJT9/90/jGw3vH4xtJ8tt/fG984/j2/N99kmz9b/5wtpcYUE3EgGoiBlQTMaCaiAHVRAyoJmJANREDqokYUE3EgGoiBlQTMaCaiAHVRAyoJmJANREDqokYUE3EgGoiBlQTMaCaiAHVRAyoJmJANREDqokYUG15cXwwPvLy67vjG0ly+s5ifOPa8/GJJMntz+bPcx/+6+34xurBZr77X5/+cH5k/tcrSXLn0Xp+ZLGZH2br/t35jfEFgEEiBlQTMaCaiAHVRAyoJmJANREDqokYUE3EgGoiBlQTMaCaiAHVRAyoJmJANREDqokYUE3EgGoiBlQTMaCaiAHVRAyoJmJANREDqokYUG2Z9fyhzsVqfCJJsn0+v7FztoHDpkl2Ti/nN17Mf2D3X80f6E2SO5/ujG8sNvC3kiTbpxfjG5e3ro1vJMnrb94c3/ASA6qJGFBNxIBqIgZUEzGgmogB1UQMqCZiQDURA6qJGFBNxIBqIgZUEzGgmogB1UQMqCZiQDURA6qJGFBNxIBqIgZUEzGgmogB1UQMqCZiQLXlzuevxkeOthfjG0my/2z+gOrWm80cUL3awGd2+rUb4xubOpy89/nZ+Mb25y/GN5JkfbA3vvHku4fjG0ly+eOX4xteYkA1EQOqiRhQTcSAaiIGVBMxoJqIAdVEDKgmYkA1EQOqiRhQTcSAaiIGVBMxoJqIAdVEDKgmYkA1EQOqiRhQTcSAaiIGVBMxoJqIAdVEDKgmYkC1ZZ69HB/ZXV2NbyTJ8uX++MZqf3d8I0lO352/Av38/fn/Yau9zVxMP/r7/EXr47O34xtJksX89ffz4/mNJPnlNx6Mb3iJAdVEDKgmYkA1EQOqiRhQTcSAaiIGVBMxoJqIAdVEDKgmYkA1EQOqiRhQTcSAaiIGVBMxoJqIAdVEDKgmYkA1EQOqiRhQTcSAaiIGVBMxoNoyuzvjI+vl9vhGkqy3NtDkzdwczdUGPrLLg/nDtpd3L8Y3kuTsxfxR49s3r49vJMn20y/GN24+3MxB64/++IPxDS8xoJqIAdVEDKgmYkA1EQOqiRhQTcSAaiIGVBMxoJqIAdVEDKgmYkA1EQOqiRhQTcSAaiIGVBMxoJqIAdVEDKgmYkA1EQOqiRhQTcSAaiIGVBMxoNoyhwfjI6uj+Y0kWe3PXzNfrOavZifJtVer8Y39/8x/XueX8xtJsv3lRmY2YvH6bHzjzicvxjeSZPf01viGlxhQTcSAaiIGVBMxoJqIAdVEDKgmYkA1EQOqiRhQTcSAaiIGVBMxoJqIAdVEDKgmYkA1EQOqiRhQTcSAaiIGVBMxoJqIAdVEDKgmYkA1EQOq/R/yx8lUEHgL6AAAAABJRU5ErkJggg==" id="image5ebad3f4b4" transform="scale(1 -1) translate(0 -219.6)" x="616.583588" y="-52.929412" width="219.6" height="219.6"/> - + @@ -1040,7 +1040,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1053,7 +1053,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1066,7 +1066,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1079,7 +1079,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1092,7 +1092,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1108,7 +1108,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1121,7 +1121,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1134,7 +1134,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1147,7 +1147,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1160,7 +1160,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1173,7 +1173,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1335,13 +1335,13 @@ z - + - + - + diff --git a/docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg b/docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg index 963d4728..d8f500d8 100644 --- a/docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg +++ b/docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg @@ -6,7 +6,7 @@ - 2024-11-21T16:50:35.154043 + 2024-11-21T17:10:48.342940 image/svg+xml @@ -37,20 +37,20 @@ L 36.72 34.56 z " style="fill: #ffffff"/> - + +iVBORw0KGgoAAAANSUhEUgAAATQAAAE0CAYAAACigc+fAAAigElEQVR4nO2dy69WZ9nGn7d7t9BWoIVSzmfYZXM+7A0FSqHAoBEVB5qoic7qxInRxJETdaROdETqxJi0cWDqIUFa01DLWc5sNsdyhs25nOTQom35/oHrt5P15Zt8T36/4cW717ve9TzrZiXXuu67tXbt2sclMGXKlCSX//znP1EfPnx41MeOHRv1f//731G/evVq1B8/jqdZZs+eHfVDhw5FfcSIEVF/5plnov7ZZ59FvZRSdu7cGfWlS5dG/Ysvvog6XVNagyNHjkT90qVLUZ88eXKj7x08eHDU6VocPXo06j/4wQ+i/vbbb0ed1uC///1v1KdOnRr1a9euRf3OnTtRf/jwYdS7urqifurUqag/9dRTUae9S987adKkqJdSys2bN6NOe2XXrl1Rp/tv6NChUW9ra4t609/2ySefRL27u7vRcehaPxFVEZH/h1jQRKQaLGgiUg0WNBGpBguaiFRDi1zOr3/96/EP9uzZE/UXXngh6uSkkXM1cODAqD/99NNRJ9dk/PjxUb97927UhwwZEvUbN25EvRR2LQ8fPhz1GTNmRP2JJ/L/K3Qt7t+/H3U619WrV0f9ww8/jPpzzz0XdbrWY8aMifr169ejfvv27ajTGhD0+W3btkV97ty5Uf/888+jTi5qq9VqdJxHjx5FfdiwYVE/d+5c1Pv7G1obWoMvfelLUe/o6Ig6OetNnWna6xcuXIg6rTE57j6hiUg1WNBEpBosaCJSDRY0EakGC5qIVEPrZz/7WXQ5yUkjh4dcxZMnT0adnLHz589HnbKi5MrQcZ588smof/zxx1F/8OBB1EspZdasWVHfvXt31OfPnx91ykKSk0P5WHJdKXtImcGXX3456r29vY2O/9prr0W9p6cn6rdu3Yo65fbI+aY1pj1ELiTp+/bti/rKlSujTnuLXO/NmzdHvZRSpk2bFvWJEydGne7LHTt2RJ0ym/S2Aq3Zs88+G3XKftJaUi6X7jGf0ESkGixoIlINFjQRqQYLmohUgwVNRKqh9d3vfjfaDqNHj45/MGjQoKjfu3cv6pQ9a9qxdubMmVGnzrTk7pATePny5aj3x5o1a6K+devWqFMnWHJ8yfk5c+ZM1ClPS8chB5qynOSk9fX1RZ3yhXQ+lLMlx4yyq7SWEyZMiDqdJ90D7e3tUaeOuJR3pPPpL8tJGUl6+2DkyJFR379/f9TJ+Sb3k34z3Wd0fHK+6ffSHvUJTUSqwYImItVgQRORarCgiUg1WNBEpBraKfdG2S3KER48eDDq1Ony+eefj3pnZ2fUaR7hihUrok75whdffDHqo0aNivqWLVuiXgp376WMHrlaH3zwQdRpRiJ1G6XMI2UJKSt68eLFqA8YMCDqV65ciTq5sa+88krUqTsp5YrJdSWHjdxG6ura9PP0e2k/kDs8ffr0qJfCczZp/5I7SQ4uXWv6zXS/Ugdaeoth3LhxUacuwPS7fEITkWqwoIlINVjQRKQaLGgiUg0WNBGphvaXXnop/gNlM8kBo3l7s2fPjjo5bOTUUYaUZktShpS+l7Klq1atinop7O7RPE3qdEquZVdXV9S3b98edbp25GjR58mZbuqYUZ6WXFeam0luIOUUHz58GHVyael7aQ9R11XqrkpdlSlz2l+umNbs7NmzjT5P2WjKVC5ZsiTqdC1GjBgRdcqcUudbejOAZt/6hCYi1WBBE5FqsKCJSDVY0ESkGixoIlINrfXr10ebgrKW5H5SdpIcLcqQUp6PHEXK7dF5kutDGVXK85XCzmvTTq10LahzKX2e8q7UyZZyrfS9lJ2ka03ON32esqvUsZZmppLDRjlC2qO0Vyg3SU45uavUdZVmZpbCHV9pLcn9bOrEf/vb3446vfVA15RcTnL66f4m99MnNBGpBguaiFSDBU1EqsGCJiLVYEETkWpopy6b1EGS3BGaVUjOGGVI33777ah3d3dHnWZaklNHztLOnTujTs5bKZz1I+haUI6N3DE6J5pTSa4oObjk4tGMRHL3aA9RV1TqejxnzpyoP3r0KOrUbblpR1xyaWkPUU6YnL3du3dHff78+VEvhc+VXEW6L0lfuXJl1GmP0m+m+5uceOpMS12hP/3006j7hCYi1WBBE5FqsKCJSDVY0ESkGixoIlINrY0bN8Ys54kTJ+IfUH6O3M9Lly5FnfJ5d+/ejTo5VHT8devWRf38+fNRJ5eT3KBSSvnRj34U9XfeeSfqTV3LO3fuRJ1ytkePHo06uYT0vXQtKFdHrh9lXWmNyS2l2aubN2+OOnVJpk685MbS+dDvIug4NH+TnL1S2A2kLCQ5tXQ/kSNOXXSHDx8edaoT1OGWnGmqK+Su+oQmItVgQRORarCgiUg1WNBEpBosaCJSDa2//vWv0XYgx4wcNnKuqEso5dvISaO5gORa0vF7e3sbfe83vvGNqJfCXXRPnz4ddXJyyClqOkOUHCpynKgjK+X2KItK+Txy3shhI+ebcrmURaXrTFlXOg51+m3q0NM8U9pz9HtL4fuPrillKo8fPx71KVOmRP3kyZNRJ9eScr/UtZnWjH4vurpRFRH5f4gFTUSqwYImItVgQRORarCgiUg1tH71q19Fm2L8+PHxD7Zt2xZ1+vz27duj3tHREXVyTQYPHhz169evR33mzJlRJyeKoCxcKexyNp3LSedKn6fOrtTBlY5P7iR1P6U1oLwrOVeURyRHi9aAvpf2BB2Hup9eu3Yt6osXL446XX/KkE6bNi3qt2/fjnop7FjTnEra75RHvXDhQtTJRSUHl9aS3E/ac5QTpr3rE5qIVIMFTUSqwYImItVgQRORarCgiUg1tFMm6tChQ1EfOXJk1MnlpKwlOU40k5DybeSmbN26NerkmpC7SnnKUjgnR91+KV86efLkqP/+97+P+pe//OWok5tG8x+pYy39ZnIPKdtIe4JygeQS0h4lN7npLErKxpILScchV5T2yYEDB6K+evXqqJfC1+7YsWNRp/wtuZnk+JJOe4i67i5cuDDq5LrS+VMW1Sc0EakGC5qIVIMFTUSqwYImItVgQRORamj99Kc/jfbeli1b4h9861vfijq5JpRHJAeMuqX29fVFnXJvlDucOnVq1ClL1l/30EmTJkWdOqCS+0nO8f3796M+ZsyYqHd2dkZ9165dUSfH9+LFi1Enh4o6wdJ8T3Kyacbqiy++GHVyFWld6DxpPuamTZuivmjRoqhTTpFcUXKTye0thTOVDx8+jDp13aVO0sOGDYs6ZSfJ5Tx8+HCj49Nev3fvXtSXL18edZ/QRKQaLGgiUg0WNBGpBguaiFSDBU1EqsGCJiLV0E6vN3zve9+LelMrnl6HoHBp04GjS5cujfo///nPqJMlfufOnagPGDAg6qXwKylkiZOtT1Y2hZdpGCy9bnH58uWoExQUpmtEIfERI0ZEnQLW9DoKvapAgWlqrDB27Nio0/lT0wAawk17i15toPOn69YfdN+8//77UafXpubMmRN1CvDTPUCtwqlBA60NDc+mRgw+oYlINVjQRKQaLGgiUg0WNBGpBguaiFRD6/vf/34Mp5OrSA4MtbCmYC65IPS9FF4l542CvzTguGn75FJKOXv2bNTJEaLBxHPnzo06uYH028aNG9fofMh9o7UhN5COT3ulqetHg5Vp4C+5tHv37o36wIEDo07r9dWvfjXqtBfJ6acW3+TglcKuYm9vb9S7urqiTk0gyNmlhgvUYp9cV9q7dHzSyS31CU1EqsGCJiLVYEETkWqwoIlINVjQRKQaWuvXr4/25JkzZ+IfkANGbaTJuaKhtQRlzygfSS4OubF0HHJFS+GWznSNaCAvnWt/rZgT1KqanDFyioYPHx51+r13796NOmVOqW06uY0TJkyIOg2zpetAmVa6/itWrIg6rQs5e+SgU+aX7qVS2CWkHCxlkWkwMQ0AHzVqVNRpr9Nw6FOnTkWd2sHTfU9r6ROaiFSDBU1EqsGCJiLVYEETkWqwoIlINbSTa0KZLvo8dZykIbdffPFFo+8lF5Jye5QXpFzd6dOno075vFL4N9AwY/oOYt68eVGn4bH79++POrmElP+j4a50HMo8UrfRtra2qNNwWsq00sBfWhfqktxfXjdBe2vDhg1RnzVrVtQpn0wOYSmcdaY1e+qpp6JO7iENLKa3EkhfsGBB1CdOnBh1yuvSWwlUb3xCE5FqsKCJSDVY0ESkGixoIlINFjQRqYZ2muVIriJ1LaXOkuTKkDNGXU63bdsWdcqYUX6RHDZyTSiLWgpnM4lJkyZFndzM9evXR3358uVRp/melJ8jN5aykHSNyIWk7Cc5zeT6kSNHriV1giV3cuHChVGnmZaUge3u7o465SnJgWyacy6F87TkNNPnb968GXXqqkyZSjo+HYfcVep4TW8f+IQmItVgQRORarCgiUg1WNBEpBosaCJSDa3f/va3MSxFXUWpmynlz3p6ehodh5yoEydORJ1yjdT9lGZIUv6POmmWwtlJ+htynD7//POokwt59OjRqJMjRI4v5eTIvaW8IP1ecojp91LXVeoQS7li0i9cuBD1tWvXRp3Wl1xa2nPkGlNX6P6ynOSA0t/Q5+ntgJkzZ0adZtDSWw/kuNMcT3obYvTo0VGnLsA+oYlINVjQRKQaLGgiUg0WNBGpBguaiFRD6xe/+EW0usiJImfsyJEjUZ8+fXrUyVUcPHhw1MnpIjeWXBw6DuXt3n333aiXUsq6deuiTnm4+fPnR526dVKelpwfcoJpPiadJ609ZVEpl0tzKin3Sw43dfql86duqXQcmkVJ7i2d57hx46JO14dcY3IUS2FXv7OzM+rkiNN9QG4jObiU5STXleoHOcF0f9O94ROaiFSDBU1EqsGCJiLVYEETkWqwoIlINbSTA0MuBWW0yAGjzpLkvJErQ44THYc63L7++utRp66uy5Yti3op7AiR40uuHHX3pGtNGUmaaUrfSy4kOWmUhXzw4EHUae0pL0jnSTrNeDxw4EDUKStKDhtdB+pkSzNi9+7dG3VyRcnpL6WUW7duRf3SpUtRJxeyo6Mj6uT4Ugaa6gTlivv6+qJOGc85c+ZE/erVq1H3CU1EqsGCJiLVYEETkWqwoIlINVjQRKQa2skpIreDcn5NHSdyX8jNpBmG5Jq89NJLUadOl+RQkRNYCs8SpKwi5c+GDBkSdXKu6FpTxpDmYxLU4ZauNf1euqb79u2LOmVdKc9H7iq5z3T9yZGjvOOaNWui3rSr8oQJE6Le33pR/pOcYMo0N83Z0rxcWhu6j8lpJueeOu7SXvcJTUSqwYImItVgQRORarCgiUg1WNBEpBraacYguSDkfpL7Mm3atKiTe0EOG7ks1AGTOmzSLERygygzVgq7ZiNHjow6dcUlyCU8d+5c1ClXR9eUspnkZJOjRfNDKf9H1+2dd96JOrmidJ4LFy6M+quvvhp1cpnHjh0bdXLKm852pd9Lbm8ppcyYMSPq5BLS/qU9sXXr1qhTppky3MePH2/0vZRbvn//ftTJyfYJTUSqwYImItVgQRORarCgiUg1WNBEpBraKQ9HOTPqIEnuIXWCbWtra6STC9LT0xN1chTJpT158mTUyV0thZ3d8ePHR526A1MujfQnn3wy6uT6kYNLLurmzZujPnz48KiTo0XdhIkVK1ZEndaS1owyp9/5znei3tXVFXVydekNAPo8XWeaH0p5ylLYyaYuyZQjpc/TWwnUfZiymTRblBzfixcvRp1cVMo5+4QmItVgQRORarCgiUg1WNBEpBosaCJSDe3kgpDrQNkwOg51miW3g5xD0uk41G2UsquUv/zoo4+i3t/f0IxB6oxKrhm5Y7QGNF9y586dUaf5mJ2dnVGn83z22WejTu5n07mZlJGk6zN37tyof/LJJ1GnvUK5Q5qnOW/evKjTelFOkd4kKKWUDz/8MOp0/9G1IzeTstEEdW0mN3bx4sVR379/f9RpZi39Lp/QRKQaLGgiUg0WNBGpBguaiFSDBU1EqqH92LFj8R+oaya5luT8UNaSvpdmTpJTRC4nOX6UdySdurGWwteC3DRybMjdO336dNTJVaRsI7mTNLu01WpFnboAf/bZZ1Ent3fdunVRp66rpNPxKbtKe7Hpnt62bVvUKctJ7jY5jVu2bIl6KTyLlLrx0n1G+VjqDkx51w8++CDqy5cvjzqtGbmitLecyyki1WNBE5FqsKCJSDVY0ESkGixoIlIN7d3d3fEfyF2gHB7l4Wg2I3UzJdeSOmDeunUr6uRQkVtK3UPJUSyFHZsbN25EnZyl0aNHR33Dhg1RX7VqVdSbOkInTpyIOrmr1ImX8oWU2zt8+HDUaZ4m7QmCugyTq0jdlmnPUfdW2uvUJZmyqOR6l8IzTWlOJbn3dE60tyg7SbNLae4unSe9GUAzUClj7ROaiFSDBU1EqsGCJiLVYEETkWqwoIlINbST47Rs2bKoDxkyJOrkgpD7SZk0ci2bzqik45MrQ44l/a5S2EEi94pcTprXSTlS+jxdC3IPybEmN5NcV5rXSV2PqSsqfS91dqXuw7SHyHmjdaRMK82OJQeSXEtymWkWZSns+pHTTHuC8qWUm6U1oOOT00zOMeVp165dG3V6k8AnNBGpBguaiFSDBU1EqsGCJiLVYEETkWpovfnmm9FyopmKlDukjCQ5PL29vVGnTrnkCJETRTrNL6RsG3UhLYU7o5IjRG5gX19f1CkbSO4n/WZyA2ktyZ2kzCNlLclJW7p0adSpaym5kAcPHmz0vTRDkhw2mrva1F0lx53yxrRPSuH5tOTe031z7ty5qD/zzDNRJ9eyqRNMn6e9TnuLnGCf0ESkGixoIlINFjQRqQYLmohUgwVNRKqhnTJR06dPjzrN+SNHiNzMjo6OqFNWbdGiRVHfv39/1GkWJWVLyX2hTpqlcCaRXDaat0gzFck5pnmaGzdujDp1CaU5ldSld/LkyVGnDrc0G5W6jdLxac/R9aG9SHlgWvtNmzZFnTrxPv3001EfNmxY1Gmvk5NZCueEm+7fmTNnRp0cWVpLWnv6beTQ09qQc2yWU0Sqx4ImItVgQRORarCgiUg1WNBEpBraKSt16NChqFOGinJyXV1dUSfHj9yagQMHRp06ylIecd68eY3OZ9asWVEvhTvHkqtIcyEpx0Zu6d/+9reok7NL7htlCWm+J82jpEwoOV2U2aRMJXVJpvOkPCJdT3ICae3pPClzStleyg/TepXCOc9du3ZFnTKYTZ1pcj+pflA+mdaG3EzKzZJL6xOaiFSDBU1EqsGCJiLVYEETkWqwoIlINWCWk+btkQvyxz/+MeqU2Rw8eHDUabbhyZMno97Z2Rl1cqIuXboUdcpHknNYSilf+9rXok7zLsl5nT17dtR37twZ9QULFkSdXEhy3ygzSHuC1ob2BM0DJVeR3Myma0nOHnUfpuPTHqUMKc20pHmjNBOXHP1SuAMt5WBv3rwZdTpXeguAfvPly5ejTllw6mBNGev33nsv6rQXfUITkWqwoIlINVjQRKQaLGgiUg0WNBGphtYPf/jD2HaVnBlyoii7RU5UU8eJnDHKwy1ZsiTqlKuj86Tup6WwG0izRcmppd9A2UPKMBLkQlJmkFxacg/JXR0wYEDUKbtK50lOM60lrT3tUdrre/fujTrtUdJpHcmB7G99qZtw04wy5Y0pK9p0jifpBGWyr1+/3uj4PqGJSDVY0ESkGixoIlINFjQRqQYLmohUQ+uXv/xldDkp60U07dZJ2ck9e/ZEfe3atVEn94VyctQ19n/TPZQcGOriSc4uZSqpiyd1fCWdXLx9+/ZFnfJ25NZRvvC1116LOu0t6gBMe4g67pJ7SJ8nV/eFF16IOjmNlCsmt3TGjBlRp1mzpbDbTw7rlClTon7q1KmoU0dqcl6bvq1A144+T52wdTlFpHosaCJSDRY0EakGC5qIVIMFTUSqoZ2yikePHo065e3IJST34uzZs1EnZ+kPf/hD1Mktpd9FmTFy2MgVLYXnTk6YMCHqlGFsa2uLOs2FvHDhQtSbOlFDhw6NOmUnqYvx48fRKC89PT1Rp46sEydOjPr/VY5w0KBBUR81alTUad4oXWeajUn3DM2+7a9jLTno9Nuosyu5h+RCknNM9xM54pTvvXv3btSprtD5+IQmItVgQRORarCgiUg1WNBEpBosaCJSDe3nz5+P/zB16tSo0xw+cn7IzSR3krJq5BQdOXIk6uvWrYs6OWY0g5Hcz1I4J3fmzJmoUy507Nix+B0J6ipKbiatzZw5c6JO2UlylmimIumUF6QMKTlgNIvy9OnTUSfXldzkgwcPRp2gbCY5h3Rv0HUohe8PctDJVaR8L609uZbkyNLnaS0p30v5ZHqTwCc0EakGC5qIVIMFTUSqwYImItVgQRORamin+XzkUlA2jPKINKOSur02dSFXrFgRdepYS3lEcqIo51dKKQ8ePIg6daCl/Bz9NpqD2Wq1ok5dg+nzNCeUPk/XgvK31MGVOvGSg07u8G9+85uor169OuqUUSVXlNxkytJ+9NFHUadsKTn3/c2C3b59e9Tnzp0bdZqZSvc9rQ3tadpDTefiLliwIOp/+ctfok73vU9oIlINFjQRqQYLmohUgwVNRKrBgiYi1dBO2TByIak7KTl15GqQ40RdQocNGxZ1cl2b5hfJIaTrUwq7V5Qz6+3tjTq5Xe+9917UOzo6or5hw4ao//rXv476jh07ok6Zzb6+vqjT2pNL2LSLKnVFJXf10qVLUae5nOQENj1/2iuUd6TP9zcLdvr06VG/ceNG1KnDLe05yt/Sfb9q1aqoX716tdH3Ug550aJFUae3IXxCE5FqsKCJSDVY0ESkGixoIlINFjQRqQYLmohUQzuFTunVA3rdglr9kuVOFj3p9FoFBaBpwPG+ffuiTmFdeiWhlObDmOk1AAp9kzVNraffeOONqNPrGRSCpldeaK9Qm+Tdu3dHnRofUOMAOj61LqfXIeh1C9rT1Eqd1pdC/bRe//rXv6JOA4hL4YYI9DoS3U9NW3bTa1zU1IH2EL36Q/WG9gq1cfcJTUSqwYImItVgQRORarCgiUg1WNBEpBpaP/nJT2LqlIK/5HY0bRdNbg25jRReJVfmiSdyrabhruSkUbC4lFKGDh0adQrkk2tJTlRXV1fUd+3aFXUa3kzuJIXQu7u7o05uILWkJieKhs2Se3j8+PFGxydnnb6XmgxQwJoc96VLl0adwu90/P5acF+7di3qdD+Re0jXlNby1VdfjTrdl6RTkwlyM8kppwYNPqGJSDVY0ESkGixoIlINFjQRqQYLmohUQ+vHP/5xdDkpDzdz5syo04BScjXIpXjrrbeiPnXq1KiTy0nnTxkzylP29PREvT8oX0ruJOVFyZUj54pc14sXLzb6XjoOOdnk0tIAXzo+DeqlvCC5ok3dWBpa21+mMkH3wPjx46NOziT9rlK4PTdlMymPSvcfvZVAOdghQ4ZE/dSpU1GnluCUvaa3FajNuk9oIlINFjQRqQYLmohUgwVNRKrBgiYi1dB64403ostJrh+5C5R5nDFjRtQPHz4cdcpUUoaNusDOnTs36pSfI0exv0HDTTustrW1RZ1yb5cvX446dUAlx5eOT+4bDa0l95B+L63NgQMHor548eKok0tLGUw6z/Pnz0ednHhykylfuHLlyqjTXqeh2seOHYt6KaVMmTIl6jQImFxL2td0f1NulvY0ubGffvpp1Cl/SxnPI0eORN0nNBGpBguaiFSDBU1EqsGCJiLVYEETkWpob5ozozwfdfEkndwRyrFRB11y5CgXSJmxl19+Oep79+6NeinswJCTQ1CmktxJcrRoLcnFI6eLcoGUgx03blzU9+zZE3XKTpK7R2t28uTJqFPul/YcOYc0Q3LatGlRpzmtH3/8cdTJHaZ1LKWUR48eRZ32BM0upXOi30adqgcNGhT1pu4q7S16u4HwCU1EqsGCJiLVYEETkWqwoIlINVjQRKQa2slVpG6d5DjNmzcv6uT8kJtC7gtlw8hhI4eK3BQ6T8qYlcKZQZrLSb+BjkNZUXKK6Dj02whyfMm9vXLlStSnT58edco20nWjPDBdH8qKrlu3LuqUX6QMKWUwm2Z4aa+TY9nfv1EX4D//+c9Rp9wsMXHixKhTF2CaEUsddGkP0f33la98Jeo+oYlINVjQRKQaLGgiUg0WNBGpBguaiFRD+9mzZ+M/kKNFc/hodiLp5CCRC0mZsffffz/q5LJQtpTm/9HvLYVnDJ47dy7q5LzOnj076uSOkbNE2UY6T3IPt2/fHvXu7u6o05rRXM4xY8ZEnRywV155Jerk4JHjvmnTpqhTd2NyAilfSOtOnXXJ6afuz6VwlpP2Kc3TJPeQ7kvaQ/TbqK6Q00/5W3Loaa/7hCYi1WBBE5FqsKCJSDVY0ESkGixoIlINrZ///OcxHEYO1axZs6JOcy0pY3bz5s2oN+322rQzJjl71PmW3M9S2LF5+PBh1Ds6OqJOmT7KGFIHWlqDhQsXRv1Pf/pT1CmTSHk+utbkgBG0luR0kTtJ508ZUuqGTJ17ae/SHqJ7hpxJchpLKWXRokVRpzmVNNuVMtyUB6Yuunfu3Ik6OeLkBNPaUP0gV9QnNBGpBguaiFSDBU1EqsGCJiLVYEETkWpoJ8eMXE6aIUnZMHKKyOEhh5DO89atW1GnLCfNFySXhZy9UkqZMGFC1Pft2xf1EydORH3Lli1R/+Y3vxl1cq4oI9nT0xP14cOHR51ys7T2AwYMiDq5nNRRdtKkSVEnh4063JLbSM7Y8ePHo04dd+k6UCfbNWvWRP13v/td1CdPnhz1UkrZunVr1JcsWRJ1yoXSfUPuJ32eHOV333036rS3aDbq1atXo05vH/iEJiLVYEETkWqwoIlINVjQRKQaLGgiUg3t5LxR/oxcFuoES04auRTUtfTevXtRJ/fzwYMHUacuoZQhpY67pZTS29sb9ZEjR0adMo90rcktpePTzFTKKtL5kNNFnXJpPiblC8mRo+tJHXFpD9GaPf/881GnLrC7d++O+oIFC6JOTuDf//73qFNOkdalFN6n9FYCXTvq6kv3GTnHNBeX3nqgvfXWW29FnWbE7tixI+o+oYlINVjQRKQaLGgiUg0WNBGpBguaiFRD680334wdaymXtnPnzqhT7u3gwYNRHzt2bNQfP46ngzm8f/zjH1GnPBx12CTHiVyWUjj/Sb+haQdacqgowzhq1Kio03lSzo8ymOfPn2/0vZQtpc669LuoMzCdP7mr5GZ2dnZGnTKzlO+lGZhz5syJOs2WpD1aCjupTefi0neTA01r03S+J+0VOk/qDkyZUJ/QRKQaLGgiUg0WNBGpBguaiFSDBU1EqqGdnCvKdJGrQblDylTS8cn9pM6VNJvx0KFDUadOtpRppetTCufhrl27FnWaeUjXiDJ9dO3IDST3jRwnciGXLl0adcqQkrtKLh6tJbmNNM+UsquUO6Tzp7Wn9aI9RNlbysZS3rgUdlj7+vqiTvudfsPt27ejTnvlypUrUacuxtR9mK4FZVdpPqlPaCJSDRY0EakGC5qIVIMFTUSqwYImItXQTl08aT4mZSqpoyVlwMipo4615HKS00hO19GjR6NOHXf7m8tJHVaXLVsW9Y0bN0ad3M9WqxV1unZN83O0xpQXJLeRZjNSHpjcSTofcrqee+65qNOea2trizq5ma+//nrUyRWdMWNG1Om60fnQmwSl8ExTygOTe0iOMt0HNF+XOuUuX7486jQDle4BmqNL955PaCJSDRY0EakGC5qIVIMFTUSqwYImItXwP7nkSx0nn/oqAAAAAElFTkSuQmCC" id="image7be2c24c71" transform="scale(1 -1) translate(0 -221.76)" x="36.72" y="-34.56" width="221.76" height="221.76"/> - - + @@ -86,7 +86,7 @@ z - + @@ -116,7 +116,7 @@ z - + @@ -156,7 +156,7 @@ z - + @@ -204,7 +204,7 @@ z - + @@ -239,7 +239,7 @@ z - + @@ -282,12 +282,12 @@ z - - + @@ -300,7 +300,7 @@ L -3.5 0 - + @@ -314,7 +314,7 @@ L -3.5 0 - + @@ -328,7 +328,7 @@ L -3.5 0 - + @@ -342,7 +342,7 @@ L -3.5 0 - + @@ -356,7 +356,7 @@ L -3.5 0 - + @@ -381,7 +381,7 @@ L 258.48 256.32 - + diff --git a/docs/assets/thumbnails/tutorials/plot_05_place_cells.svg b/docs/assets/thumbnails/tutorials/plot_05_place_cells.svg index b95331b7..c089d9e7 100644 --- a/docs/assets/thumbnails/tutorials/plot_05_place_cells.svg +++ b/docs/assets/thumbnails/tutorials/plot_05_place_cells.svg @@ -6,7 +6,7 @@ - 2024-11-21T16:50:55.081995 + 2024-11-21T17:11:02.852574 image/svg+xml @@ -141,7 +141,7 @@ L 163.282375 89.992092 L 150.859369 90.452067 L 138.436364 86.592956 z -" clip-path="url(#p572823fb5c)" style="fill: #1f77b4"/> +" clip-path="url(#p0e3c4db3b6)" style="fill: #1f77b4"/> @@ -269,7 +269,7 @@ L 163.282375 95.546095 L 150.859369 95.546095 L 138.436364 91.686983 z -" clip-path="url(#ped722a87a1)" style="fill: #1f77b4"/> +" clip-path="url(#pf0e2cb30bb)" style="fill: #1f77b4"/> @@ -397,7 +397,7 @@ L 163.282375 98.516288 L 150.859369 97.387854 L 138.436364 96.781011 z -" clip-path="url(#p209beddc41)" style="fill: #1f77b4"/> +" clip-path="url(#pa2e8401478)" style="fill: #1f77b4"/> @@ -525,7 +525,7 @@ L 163.282375 105.128713 L 150.859369 103.78146 L 138.436364 101.875038 z -" clip-path="url(#p283ef4ee22)" style="fill: #1f77b4"/> +" clip-path="url(#pdc2a28f725)" style="fill: #1f77b4"/> @@ -653,7 +653,7 @@ L 163.282375 109.944734 L 150.859369 108.163866 L 138.436364 106.969066 z -" clip-path="url(#p66e4bc9bd9)" style="fill: #1f77b4"/> +" clip-path="url(#p6d2a2cf141)" style="fill: #1f77b4"/> @@ -781,7 +781,7 @@ L 163.282375 112.873397 L 150.859369 112.335632 L 138.436364 112.063093 z -" clip-path="url(#p3281d5b33b)" style="fill: #1f77b4"/> +" clip-path="url(#pa20cedf5e1)" style="fill: #1f77b4"/> @@ -909,7 +909,7 @@ L 163.282375 119.118836 L 150.859369 117.422188 L 138.436364 117.157121 z -" clip-path="url(#pac685ed94b)" style="fill: #1f77b4"/> +" clip-path="url(#p7f08843877)" style="fill: #1f77b4"/> @@ -1037,7 +1037,7 @@ L 163.282375 124.866066 L 150.859369 123.148398 L 138.436364 122.251149 z -" clip-path="url(#pd7d3117bb9)" style="fill: #1f77b4"/> +" clip-path="url(#pf5ed78058e)" style="fill: #1f77b4"/> @@ -1165,7 +1165,7 @@ L 163.282375 130.031018 L 150.859369 128.568937 L 138.436364 127.345176 z -" clip-path="url(#p1104e6bb76)" style="fill: #1f77b4"/> +" clip-path="url(#pe043fdbffb)" style="fill: #1f77b4"/> @@ -1293,7 +1293,7 @@ L 163.282375 134.247076 L 150.859369 133.904036 L 138.436364 132.439204 z -" clip-path="url(#p354a867612)" style="fill: #1f77b4"/> +" clip-path="url(#pf135300692)" style="fill: #1f77b4"/> @@ -1421,7 +1421,7 @@ L 163.282375 138.321252 L 150.859369 137.533231 L 138.436364 138.872534 z -" clip-path="url(#pbc38ee0667)" style="fill: #1f77b4"/> +" clip-path="url(#pcb1b8af3f4)" style="fill: #1f77b4"/> @@ -1549,7 +1549,7 @@ L 163.282375 143.018307 L 150.859369 142.627259 L 138.436364 143.441972 z -" clip-path="url(#pc3df7eea2e)" style="fill: #1f77b4"/> +" clip-path="url(#p632a40123f)" style="fill: #1f77b4"/> @@ -1677,7 +1677,7 @@ L 163.282375 147.721286 L 150.859369 149.890333 L 138.436364 150.910121 z -" clip-path="url(#p09d277e4c4)" style="fill: #1f77b4"/> +" clip-path="url(#p4f18ef3499)" style="fill: #1f77b4"/> @@ -1805,7 +1805,7 @@ L 163.282375 152.815314 L 150.859369 154.134299 L 138.436364 155.833457 z -" clip-path="url(#p6851f068b5)" style="fill: #1f77b4"/> +" clip-path="url(#pac2f680d9c)" style="fill: #1f77b4"/> @@ -1933,7 +1933,7 @@ L 163.282375 157.909342 L 150.859369 160.154496 L 138.436364 161.474114 z -" clip-path="url(#p62104534f6)" style="fill: #1f77b4"/> +" clip-path="url(#pf83d055c07)" style="fill: #1f77b4"/> @@ -2061,7 +2061,7 @@ L 163.282375 163.003369 L 150.859369 164.886826 L 138.436364 165.554307 z -" clip-path="url(#pafb98e4a97)" style="fill: #1f77b4"/> +" clip-path="url(#p038e4ff393)" style="fill: #1f77b4"/> @@ -2189,7 +2189,7 @@ L 163.282375 168.097397 L 150.859369 169.511636 L 138.436364 171.404623 z -" clip-path="url(#pb789db8db0)" style="fill: #1f77b4"/> +" clip-path="url(#p09f1676ff4)" style="fill: #1f77b4"/> @@ -2317,7 +2317,7 @@ L 163.282375 174.434254 L 150.859369 173.77534 L 138.436364 174.716213 z -" clip-path="url(#pc21b3ed704)" style="fill: #1f77b4"/> +" clip-path="url(#p86f59c37d1)" style="fill: #1f77b4"/> @@ -2445,7 +2445,7 @@ L 163.282375 179.441196 L 150.859369 178.610596 L 138.436364 180.43751 z -" clip-path="url(#pb6c9b0b585)" style="fill: #1f77b4"/> +" clip-path="url(#peaa58a2cc3)" style="fill: #1f77b4"/> @@ -2573,7 +2573,7 @@ L 163.282375 184.220139 L 150.859369 185.504664 L 138.436364 185.803448 z -" clip-path="url(#pac8dd561ac)" style="fill: #1f77b4"/> +" clip-path="url(#p29cbbe9ac5)" style="fill: #1f77b4"/> @@ -2701,7 +2701,7 @@ L 163.282375 189.151042 L 150.859369 189.321551 L 138.436364 189.774823 z -" clip-path="url(#p156aab9f8a)" style="fill: #1f77b4"/> +" clip-path="url(#pa7d34e827e)" style="fill: #1f77b4"/> @@ -2829,7 +2829,7 @@ L 163.282375 193.999387 L 150.859369 193.917508 L 138.436364 195.393527 z -" clip-path="url(#pd2801dea5e)" style="fill: #1f77b4"/> +" clip-path="url(#pdadc6caba6)" style="fill: #1f77b4"/> @@ -2957,7 +2957,7 @@ L 163.282375 199.083864 L 150.859369 199.861339 L 138.436364 201.34009 z -" clip-path="url(#pf7bb0ce9c8)" style="fill: #1f77b4"/> +" clip-path="url(#pc8d9835216)" style="fill: #1f77b4"/> @@ -3085,7 +3085,7 @@ L 163.282375 204.409595 L 150.859369 204.626847 L 138.436364 205.752847 z -" clip-path="url(#p1b07ee276c)" style="fill: #1f77b4"/> +" clip-path="url(#p8e16da2b72)" style="fill: #1f77b4"/> @@ -3213,7 +3213,7 @@ L 163.282375 211.436043 L 150.859369 211.457761 L 138.436364 211.187977 z -" clip-path="url(#p2a602b10c5)" style="fill: #1f77b4"/> +" clip-path="url(#p18c5b61c55)" style="fill: #1f77b4"/> @@ -3341,7 +3341,7 @@ L 163.282375 216.648408 L 150.859369 216.35221 L 138.436364 217.0824 z -" clip-path="url(#p34bf02b7d9)" style="fill: #1f77b4"/> +" clip-path="url(#p254d2ae3ee)" style="fill: #1f77b4"/> @@ -3469,7 +3469,7 @@ L 163.282375 219.96929 L 150.859369 220.341077 L 138.436364 221.536938 z -" clip-path="url(#pba353626c9)" style="fill: #1f77b4"/> +" clip-path="url(#p22082e1379)" style="fill: #1f77b4"/> @@ -3597,7 +3597,7 @@ L 163.282375 226.523396 L 150.859369 226.543693 L 138.436364 226.930503 z -" clip-path="url(#p614256478f)" style="fill: #1f77b4"/> +" clip-path="url(#p41357bc99b)" style="fill: #1f77b4"/> @@ -3725,7 +3725,7 @@ L 163.282375 231.091986 L 150.859369 230.330212 L 138.436364 232.134856 z -" clip-path="url(#p15c2360490)" style="fill: #1f77b4"/> +" clip-path="url(#pd005daddb9)" style="fill: #1f77b4"/> @@ -3853,7 +3853,7 @@ L 163.282375 236.953139 L 150.859369 237.117517 L 138.436364 237.372938 z -" clip-path="url(#pb30e07beae)" style="fill: #1f77b4"/> +" clip-path="url(#p9980bdc2c9)" style="fill: #1f77b4"/> @@ -3981,7 +3981,7 @@ L 163.282375 242.633186 L 150.859369 242.314969 L 138.436364 242.84597 z -" clip-path="url(#p1bad7bb91d)" style="fill: #1f77b4"/> +" clip-path="url(#p8c674b7111)" style="fill: #1f77b4"/> @@ -4109,7 +4109,7 @@ L 163.282375 248.182006 L 150.859369 247.514921 L 138.436364 246.392398 z -" clip-path="url(#p1123924964)" style="fill: #1f77b4"/> +" clip-path="url(#p6757dd4eec)" style="fill: #1f77b4"/> @@ -4237,7 +4237,7 @@ L 163.282375 252.788528 L 150.859369 252.345603 L 138.436364 253.460949 z -" clip-path="url(#pa81bfca643)" style="fill: #1f77b4"/> +" clip-path="url(#p385b3ce1d3)" style="fill: #1f77b4"/> @@ -4365,7 +4365,7 @@ L 163.282375 258.2069 L 150.859369 258.378563 L 138.436364 258.342591 z -" clip-path="url(#peb68f0f3d5)" style="fill: #1f77b4"/> +" clip-path="url(#pe32d81a0d7)" style="fill: #1f77b4"/> @@ -4493,7 +4493,7 @@ L 163.282375 261.873813 L 150.859369 262.194923 L 138.436364 262.926893 z -" clip-path="url(#pc9368afb0e)" style="fill: #1f77b4"/> +" clip-path="url(#p2f60b72342)" style="fill: #1f77b4"/> @@ -4621,7 +4621,7 @@ L 163.282375 268.436002 L 150.859369 268.640149 L 138.436364 268.668522 z -" clip-path="url(#pdb01fb6180)" style="fill: #1f77b4"/> +" clip-path="url(#p8b8d832aa4)" style="fill: #1f77b4"/> @@ -4749,7 +4749,7 @@ L 163.282375 272.736498 L 150.859369 273.112653 L 138.436364 273.177522 z -" clip-path="url(#pa1da50f6ad)" style="fill: #1f77b4"/> +" clip-path="url(#pe569db8b33)" style="fill: #1f77b4"/> @@ -4877,7 +4877,7 @@ L 163.282375 278.50536 L 150.859369 278.27724 L 138.436364 278.60638 z -" clip-path="url(#p518ebee74d)" style="fill: #1f77b4"/> +" clip-path="url(#p997f2efd30)" style="fill: #1f77b4"/> @@ -5005,7 +5005,7 @@ L 163.282375 280.96861 L 150.859369 280.997298 L 138.436364 282.101848 z -" clip-path="url(#p3f5f95ca82)" style="fill: #1f77b4"/> +" clip-path="url(#p29c64d0a0a)" style="fill: #1f77b4"/> @@ -5133,7 +5133,7 @@ L 163.282375 288.899983 L 150.859369 289.119142 L 138.436364 289.119142 z -" clip-path="url(#pdc05f791cc)" style="fill: #1f77b4"/> +" clip-path="url(#p89841cc475)" style="fill: #1f77b4"/> @@ -5261,7 +5261,7 @@ L 163.282375 291.583257 L 150.859369 293.001435 L 138.436364 293.711703 z -" clip-path="url(#pd3aaa8e066)" style="fill: #1f77b4"/> +" clip-path="url(#p919af6800c)" style="fill: #1f77b4"/> @@ -5389,7 +5389,7 @@ L 163.282375 299.142828 L 150.859369 299.155731 L 138.436364 299.307198 z -" clip-path="url(#p779a806592)" style="fill: #1f77b4"/> +" clip-path="url(#pe1ecb1d528)" style="fill: #1f77b4"/> @@ -5517,7 +5517,7 @@ L 163.282375 303.68113 L 150.859369 304.055015 L 138.436364 304.257949 z -" clip-path="url(#p819877d911)" style="fill: #1f77b4"/> +" clip-path="url(#p9afb1a7ac7)" style="fill: #1f77b4"/> @@ -5645,7 +5645,7 @@ L 163.282375 308.595546 L 150.859369 308.857498 L 138.436364 309.284109 z -" clip-path="url(#pabf4d4239f)" style="fill: #1f77b4"/> +" clip-path="url(#pbceb632149)" style="fill: #1f77b4"/> @@ -5773,7 +5773,7 @@ L 163.282375 314.556022 L 150.859369 314.558632 L 138.436364 314.58928 z -" clip-path="url(#p3c00e4a159)" style="fill: #1f77b4"/> +" clip-path="url(#pb1f81209a8)" style="fill: #1f77b4"/> @@ -5901,7 +5901,7 @@ L 163.282375 319.683308 L 150.859369 319.611416 L 138.436364 319.445293 z -" clip-path="url(#p06959f1930)" style="fill: #1f77b4"/> +" clip-path="url(#pad345cccfb)" style="fill: #1f77b4"/> @@ -6029,7 +6029,7 @@ L 163.282375 324.588668 L 150.859369 324.603478 L 138.436364 324.597462 z -" clip-path="url(#p7142e3d0a8)" style="fill: #1f77b4"/> +" clip-path="url(#p95e4e3f925)" style="fill: #1f77b4"/> @@ -6157,7 +6157,7 @@ L 163.282375 329.71414 L 150.859369 329.146956 L 138.436364 326.393802 z -" clip-path="url(#p782bc26d76)" style="fill: #1f77b4"/> +" clip-path="url(#p2305b25473)" style="fill: #1f77b4"/> @@ -6285,7 +6285,7 @@ L 163.282375 334.521814 L 150.859369 334.515759 L 138.436364 334.62707 z -" clip-path="url(#p91628cf94d)" style="fill: #1f77b4"/> +" clip-path="url(#pb88177550f)" style="fill: #1f77b4"/> @@ -6413,7 +6413,7 @@ L 163.282375 340.059418 L 150.859369 339.532577 L 138.436364 339.841389 z -" clip-path="url(#p2910e27da5)" style="fill: #1f77b4"/> +" clip-path="url(#p6499365c8e)" style="fill: #1f77b4"/> @@ -6541,7 +6541,7 @@ L 163.282375 344.702088 L 150.859369 344.848432 L 138.436364 344.946892 z -" clip-path="url(#p4c6dbbe861)" style="fill: #1f77b4"/> +" clip-path="url(#p4ee8bd8c39)" style="fill: #1f77b4"/> @@ -6669,7 +6669,7 @@ L 163.282375 349.763893 L 150.859369 350.056493 L 138.436364 349.799605 z -" clip-path="url(#p190eb5514a)" style="fill: #1f77b4"/> +" clip-path="url(#p1f874ef36a)" style="fill: #1f77b4"/> @@ -6797,7 +6797,7 @@ L 163.282375 355.224923 L 150.859369 355.09084 L 138.436364 355.015479 z -" clip-path="url(#p021ab88ae5)" style="fill: #1f77b4"/> +" clip-path="url(#p68931db2c6)" style="fill: #1f77b4"/> @@ -6925,7 +6925,7 @@ L 163.282375 359.542475 L 150.859369 358.925051 L 138.436364 359.01289 z -" clip-path="url(#p3bc5ff6c12)" style="fill: #1f77b4"/> +" clip-path="url(#p314a4fa0be)" style="fill: #1f77b4"/> @@ -7053,7 +7053,7 @@ L 163.282375 365.529556 L 150.859369 363.079744 L 138.436364 362.488053 z -" clip-path="url(#p4ad6bf8eff)" style="fill: #1f77b4"/> +" clip-path="url(#p7a7c8a7734)" style="fill: #1f77b4"/> @@ -7181,7 +7181,7 @@ L 163.282375 370.623583 L 150.859369 370.623583 L 138.436364 370.370125 z -" clip-path="url(#pcf5e04a82c)" style="fill: #1f77b4"/> +" clip-path="url(#pe5225c95d6)" style="fill: #1f77b4"/> @@ -7309,7 +7309,7 @@ L 163.282375 375.488923 L 150.859369 375.19077 L 138.436364 375.281553 z -" clip-path="url(#pfadda881d9)" style="fill: #1f77b4"/> +" clip-path="url(#pe6cf8f9895)" style="fill: #1f77b4"/> @@ -7437,7 +7437,7 @@ L 163.282375 379.611026 L 150.859369 380.074061 L 138.436364 380.201158 z -" clip-path="url(#p27d8c0f617)" style="fill: #1f77b4"/> +" clip-path="url(#pc3dcabef4f)" style="fill: #1f77b4"/> @@ -7565,7 +7565,7 @@ L 163.282375 385.864216 L 150.859369 385.86747 L 138.436364 385.874052 z -" clip-path="url(#p0b6faa1ba0)" style="fill: #1f77b4"/> +" clip-path="url(#p1a22f8e4a6)" style="fill: #1f77b4"/> @@ -7693,7 +7693,7 @@ L 163.282375 390.999694 L 150.859369 390.999694 L 138.436364 390.999694 z -" clip-path="url(#pdcc35b6ff2)" style="fill: #1f77b4"/> +" clip-path="url(#p22305e73a0)" style="fill: #1f77b4"/> @@ -7821,7 +7821,7 @@ L 163.282375 396.093721 L 150.859369 396.093721 L 138.436364 396.093721 z -" clip-path="url(#pa46da6aada)" style="fill: #1f77b4"/> +" clip-path="url(#p624d444f0f)" style="fill: #1f77b4"/> @@ -7949,7 +7949,7 @@ L 163.282375 399.81562 L 150.859369 399.92333 L 138.436364 397.786498 z -" clip-path="url(#p311eb8fd3f)" style="fill: #1f77b4"/> +" clip-path="url(#p6cc4bc6346)" style="fill: #1f77b4"/> @@ -8077,7 +8077,7 @@ L 163.282375 406.039391 L 150.859369 406.159944 L 138.436364 406.214551 z -" clip-path="url(#pb983719fca)" style="fill: #1f77b4"/> +" clip-path="url(#p6954ad7320)" style="fill: #1f77b4"/> @@ -8205,7 +8205,7 @@ L 163.282375 411.222154 L 150.859369 410.951038 L 138.436364 410.760554 z -" clip-path="url(#p844e5023b9)" style="fill: #1f77b4"/> +" clip-path="url(#p54f71c7bca)" style="fill: #1f77b4"/> @@ -8333,7 +8333,7 @@ L 163.282375 416.469832 L 150.859369 416.469832 L 138.436364 416.469832 z -" clip-path="url(#pf7b8f24b3f)" style="fill: #1f77b4"/> +" clip-path="url(#pc3c7e8ea35)" style="fill: #1f77b4"/> @@ -8461,7 +8461,7 @@ L 163.282375 419.059984 L 150.859369 419.011074 L 138.436364 419.329063 z -" clip-path="url(#p7ef8b3de81)" style="fill: #1f77b4"/> +" clip-path="url(#p172e3ef015)" style="fill: #1f77b4"/> @@ -8589,7 +8589,7 @@ L 163.282375 425.56209 L 150.859369 425.850064 L 138.436364 425.320643 z -" clip-path="url(#p24b163fe8d)" style="fill: #1f77b4"/> +" clip-path="url(#p2f4219f82d)" style="fill: #1f77b4"/> @@ -8717,7 +8717,7 @@ L 163.282375 431.751914 L 150.859369 431.751914 L 138.436364 431.667973 z -" clip-path="url(#p811ff56be2)" style="fill: #1f77b4"/> +" clip-path="url(#p039387faa8)" style="fill: #1f77b4"/> @@ -8845,7 +8845,7 @@ L 163.282375 436.682896 L 150.859369 436.789599 L 138.436364 436.845942 z -" clip-path="url(#p2cf7ba3b65)" style="fill: #1f77b4"/> +" clip-path="url(#p6e24c38f01)" style="fill: #1f77b4"/> @@ -8973,7 +8973,7 @@ L 163.282375 439.673099 L 150.859369 439.474353 L 138.436364 440.919594 z -" clip-path="url(#p03611a99b1)" style="fill: #1f77b4"/> +" clip-path="url(#pb72267fbdf)" style="fill: #1f77b4"/> @@ -9101,7 +9101,7 @@ L 163.282375 447.033997 L 150.859369 447.033997 L 138.436364 447.033997 z -" clip-path="url(#p837a5a75eb)" style="fill: #1f77b4"/> +" clip-path="url(#p2151eb46be)" style="fill: #1f77b4"/> @@ -9229,7 +9229,7 @@ L 163.282375 451.290097 L 150.859369 451.024951 L 138.436364 451.215028 z -" clip-path="url(#p7c523094ef)" style="fill: #1f77b4"/> +" clip-path="url(#p6854fb00b6)" style="fill: #1f77b4"/> @@ -9357,7 +9357,7 @@ L 163.282375 455.093982 L 150.859369 453.986369 L 138.436364 455.030861 z -" clip-path="url(#p798d5edbc6)" style="fill: #1f77b4"/> +" clip-path="url(#p127aacfc69)" style="fill: #1f77b4"/> @@ -9485,7 +9485,7 @@ L 163.282375 461.11904 L 150.859369 461.654235 L 138.436364 459.394492 z -" clip-path="url(#pce1ff347c2)" style="fill: #1f77b4"/> +" clip-path="url(#p4d2d0e9a15)" style="fill: #1f77b4"/> @@ -9613,7 +9613,7 @@ L 163.282375 466.609699 L 150.859369 466.303741 L 138.436364 466.723316 z -" clip-path="url(#pa705be4e51)" style="fill: #1f77b4"/> +" clip-path="url(#pb889106f32)" style="fill: #1f77b4"/> @@ -9741,7 +9741,7 @@ L 163.282375 471.903828 L 150.859369 471.858754 L 138.436364 470.901622 z -" clip-path="url(#p3754c5452d)" style="fill: #1f77b4"/> +" clip-path="url(#p056b5ea1d7)" style="fill: #1f77b4"/> @@ -9869,7 +9869,7 @@ L 163.282375 477.140786 L 150.859369 476.755216 L 138.436364 477.249316 z -" clip-path="url(#p6070149729)" style="fill: #1f77b4"/> +" clip-path="url(#p44a614b5e9)" style="fill: #1f77b4"/> @@ -9997,7 +9997,7 @@ L 163.282375 482.311639 L 150.859369 482.69219 L 138.436364 482.305189 z -" clip-path="url(#pdbcc2c09f9)" style="fill: #1f77b4"/> +" clip-path="url(#p8f192c384b)" style="fill: #1f77b4"/> @@ -10125,7 +10125,7 @@ L 163.282375 487.697601 L 150.859369 487.296255 L 138.436364 487.65104 z -" clip-path="url(#p31610612d6)" style="fill: #1f77b4"/> +" clip-path="url(#pd1187d87f8)" style="fill: #1f77b4"/> @@ -10253,7 +10253,7 @@ L 163.282375 492.500459 L 150.859369 492.394171 L 138.436364 492.815875 z -" clip-path="url(#p1454def9d7)" style="fill: #1f77b4"/> +" clip-path="url(#p9f69815762)" style="fill: #1f77b4"/> @@ -10381,7 +10381,7 @@ L 163.282375 497.088106 L 150.859369 497.565971 L 138.436364 497.298383 z -" clip-path="url(#p4a8c61d316)" style="fill: #1f77b4"/> +" clip-path="url(#pac1a31e28e)" style="fill: #1f77b4"/> @@ -10509,7 +10509,7 @@ L 163.282375 501.880392 L 150.859369 502.122913 L 138.436364 502.738834 z -" clip-path="url(#pd4869d639f)" style="fill: #1f77b4"/> +" clip-path="url(#p8ee524bb5f)" style="fill: #1f77b4"/> @@ -10637,7 +10637,7 @@ L 163.282375 508.162328 L 150.859369 507.760611 L 138.436364 506.832351 z -" clip-path="url(#pc5f801ed07)" style="fill: #1f77b4"/> +" clip-path="url(#p10e718ea87)" style="fill: #1f77b4"/> @@ -10765,7 +10765,7 @@ L 163.282375 513.256355 L 150.859369 513.055497 L 138.436364 513.256355 z -" clip-path="url(#pd45cd6c4b0)" style="fill: #1f77b4"/> +" clip-path="url(#p9d9e96a237)" style="fill: #1f77b4"/> @@ -10893,7 +10893,7 @@ L 163.282375 517.962884 L 150.859369 518.171842 L 138.436364 518.12872 z -" clip-path="url(#p380d0d31a2)" style="fill: #1f77b4"/> +" clip-path="url(#p101e5d8bcc)" style="fill: #1f77b4"/> @@ -11021,7 +11021,7 @@ L 163.282375 523.117458 L 150.859369 523.343981 L 138.436364 523.361287 z -" clip-path="url(#p277198b342)" style="fill: #1f77b4"/> +" clip-path="url(#p8d81371afa)" style="fill: #1f77b4"/> @@ -11149,7 +11149,7 @@ L 163.282375 528.538438 L 150.859369 527.254263 L 138.436364 525.349765 z -" clip-path="url(#p79cb8cb630)" style="fill: #1f77b4"/> +" clip-path="url(#p912f483b93)" style="fill: #1f77b4"/> @@ -11277,7 +11277,7 @@ L 163.282375 533.513634 L 150.859369 533.562782 L 138.436364 533.55831 z -" clip-path="url(#pc814d5bcb1)" style="fill: #1f77b4"/> +" clip-path="url(#pa5c2229cd2)" style="fill: #1f77b4"/> @@ -11405,7 +11405,7 @@ L 163.282375 538.593772 L 150.859369 538.634766 L 138.436364 538.675879 z -" clip-path="url(#pa26a1bbd1b)" style="fill: #1f77b4"/> +" clip-path="url(#pe1054f0950)" style="fill: #1f77b4"/> @@ -11533,7 +11533,7 @@ L 163.282375 542.357274 L 150.859369 542.523997 L 138.436364 542.210854 z -" clip-path="url(#p458b15482e)" style="fill: #1f77b4"/> +" clip-path="url(#pe5aa5b3bd6)" style="fill: #1f77b4"/> @@ -11661,7 +11661,7 @@ L 163.282375 548.801991 L 150.859369 548.914548 L 138.436364 548.914548 z -" clip-path="url(#p19a045ca94)" style="fill: #1f77b4"/> +" clip-path="url(#pd59997137c)" style="fill: #1f77b4"/> @@ -11789,7 +11789,7 @@ L 163.282375 553.751302 L 150.859369 553.652958 L 138.436364 553.861406 z -" clip-path="url(#p4dd2b01238)" style="fill: #1f77b4"/> +" clip-path="url(#pc8ab45e284)" style="fill: #1f77b4"/> @@ -11917,7 +11917,7 @@ L 163.282375 558.920692 L 150.859369 559.102603 L 138.436364 559.102603 z -" clip-path="url(#p2305d6e79c)" style="fill: #1f77b4"/> +" clip-path="url(#p7e893c518d)" style="fill: #1f77b4"/> @@ -12045,7 +12045,7 @@ L 163.282375 563.446248 L 150.859369 563.966138 L 138.436364 564.005856 z -" clip-path="url(#pa27958c57b)" style="fill: #1f77b4"/> +" clip-path="url(#pfcccc66c32)" style="fill: #1f77b4"/> @@ -12173,7 +12173,7 @@ L 163.282375 568.679235 L 150.859369 568.829672 L 138.436364 569.036291 z -" clip-path="url(#pb47e1a225f)" style="fill: #1f77b4"/> +" clip-path="url(#pa8e44591d6)" style="fill: #1f77b4"/> @@ -12301,7 +12301,7 @@ L 163.282375 572.717169 L 150.859369 571.772432 L 138.436364 571.077914 z -" clip-path="url(#pe175a5471e)" style="fill: #1f77b4"/> +" clip-path="url(#p5903aa2a41)" style="fill: #1f77b4"/> @@ -12429,7 +12429,7 @@ L 163.282375 579.478714 L 150.859369 579.478714 L 138.436364 579.478714 z -" clip-path="url(#peb3e6e1a42)" style="fill: #1f77b4"/> +" clip-path="url(#pb967ced3b4)" style="fill: #1f77b4"/> @@ -12557,7 +12557,7 @@ L 163.282375 584.572741 L 150.859369 584.572741 L 138.436364 584.572741 z -" clip-path="url(#p09958e5e6b)" style="fill: #1f77b4"/> +" clip-path="url(#p055bcd36e5)" style="fill: #1f77b4"/> @@ -12685,7 +12685,7 @@ L 163.282375 589.123635 L 150.859369 589.499936 L 138.436364 588.976344 z -" clip-path="url(#p60bdbbacdc)" style="fill: #1f77b4"/> +" clip-path="url(#pda9e973318)" style="fill: #1f77b4"/> @@ -12813,7 +12813,7 @@ L 163.282375 593.97332 L 150.859369 593.644395 L 138.436364 594.229481 z -" clip-path="url(#pc3a2be4df9)" style="fill: #1f77b4"/> +" clip-path="url(#pf5cc905880)" style="fill: #1f77b4"/> @@ -12941,7 +12941,7 @@ L 163.282375 599.582236 L 150.859369 599.491993 L 138.436364 599.346609 z -" clip-path="url(#p80a7549bc7)" style="fill: #1f77b4"/> +" clip-path="url(#p3a80d86090)" style="fill: #1f77b4"/> @@ -13069,7 +13069,7 @@ L 163.282375 604.736839 L 150.859369 604.948851 L 138.436364 604.948851 z -" clip-path="url(#pb02efedd08)" style="fill: #1f77b4"/> +" clip-path="url(#p874cdb5ffd)" style="fill: #1f77b4"/> @@ -13197,7 +13197,7 @@ L 163.282375 610.042879 L 150.859369 610.042879 L 138.436364 610.015928 z -" clip-path="url(#pa264f387a9)" style="fill: #1f77b4"/> +" clip-path="url(#pd31b1ae334)" style="fill: #1f77b4"/> @@ -13325,7 +13325,7 @@ L 163.282375 613.569142 L 150.859369 613.884836 L 138.436364 614.818039 z -" clip-path="url(#p8d46995f83)" style="fill: #1f77b4"/> +" clip-path="url(#pf520ee413d)" style="fill: #1f77b4"/> @@ -13453,7 +13453,7 @@ L 163.282375 619.673507 L 150.859369 617.919418 L 138.436364 618.105152 z -" clip-path="url(#pb35d892304)" style="fill: #1f77b4"/> +" clip-path="url(#pf89c1d9f7b)" style="fill: #1f77b4"/> @@ -13581,7 +13581,7 @@ L 163.282375 625.243387 L 150.859369 625.24979 L 138.436364 625.044981 z -" clip-path="url(#pefdacb42e5)" style="fill: #1f77b4"/> +" clip-path="url(#pd725f28ee7)" style="fill: #1f77b4"/> @@ -13709,7 +13709,7 @@ L 163.282375 630.418989 L 150.859369 630.418989 L 138.436364 630.418989 z -" clip-path="url(#p0bc423c0e1)" style="fill: #1f77b4"/> +" clip-path="url(#p26e4c95d86)" style="fill: #1f77b4"/> @@ -13837,7 +13837,7 @@ L 163.282375 635.513017 L 150.859369 635.384599 L 138.436364 635.513017 z -" clip-path="url(#pbe71e0fd56)" style="fill: #1f77b4"/> +" clip-path="url(#p064f6d41b2)" style="fill: #1f77b4"/> @@ -13965,18 +13965,18 @@ L 163.282375 639.998942 L 150.859369 639.486309 L 138.436364 638.635865 z -" clip-path="url(#pd82b7b5f3d)" style="fill: #1f77b4"/> +" clip-path="url(#p911065e36b)" style="fill: #1f77b4"/> - - + @@ -14012,7 +14012,7 @@ z - + @@ -14052,7 +14052,7 @@ z - + @@ -14087,7 +14087,7 @@ z - + @@ -14133,7 +14133,7 @@ z - + @@ -14188,7 +14188,7 @@ z - + @@ -14219,7 +14219,7 @@ z - + @@ -14234,7 +14234,7 @@ z - + @@ -14249,7 +14249,7 @@ z - + @@ -14500,331 +14500,331 @@ L 777.6 640.8 - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg b/docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg index 369982b1..97755fe2 100644 --- a/docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg +++ b/docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg @@ -6,7 +6,7 @@ - 2024-11-21T16:53:44.508011 + 2024-11-21T17:11:24.024905 image/svg+xml @@ -41,12 +41,12 @@ z - - + @@ -82,7 +82,7 @@ z - + @@ -111,7 +111,7 @@ z - + @@ -150,7 +150,7 @@ z - + @@ -197,7 +197,7 @@ z - + @@ -231,7 +231,7 @@ z - + @@ -271,7 +271,7 @@ z - + @@ -590,12 +590,12 @@ z - - + @@ -619,7 +619,7 @@ z - + @@ -634,7 +634,7 @@ z - + @@ -649,7 +649,7 @@ z - + @@ -664,7 +664,7 @@ z - + @@ -679,7 +679,7 @@ z - + @@ -694,7 +694,7 @@ z - + @@ -709,7 +709,7 @@ z - + @@ -736,7 +736,7 @@ z - + @@ -1003,7 +1003,7 @@ L 390.302704 275.526196 L 393.030894 278.943558 L 395.759083 277.90626 L 398.487273 270.043746 -" clip-path="url(#p5725006008)" style="fill: none; stroke: #ff0000; stroke-width: 2; stroke-linecap: square"/> +" clip-path="url(#pce426ebda3)" style="fill: none; stroke: #ff0000; stroke-width: 2; stroke-linecap: square"/> +" clip-path="url(#pce426ebda3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pce426ebda3)" style="fill: none; stroke: #008000; stroke-opacity: 0.5; stroke-width: 1.5; stroke-linecap: square"/> + diff --git a/docs/background/plot_00_conceptual_intro.md b/docs/background/plot_00_conceptual_intro.md index 193a5a4c..686d7903 100644 --- a/docs/background/plot_00_conceptual_intro.md +++ b/docs/background/plot_00_conceptual_intro.md @@ -15,6 +15,29 @@ kernelspec: :tags: [hide-input] %matplotlib inline +import warnings + +# Ignore the first specific warning +warnings.filterwarnings( + "ignore", + message="plotting functions contained within `_documentation_utils` are intended for nemos's documentation.", + category=UserWarning, +) + +# Ignore the second specific warning +warnings.filterwarnings( + "ignore", + message="Ignoring cached namespace 'core'", + category=UserWarning, +) + +warnings.filterwarnings( + "ignore", + message=( + "invalid value encountered in div " + ), + category=RuntimeWarning, +) ``` (glm_intro_background)= # Generalized Linear Models: An Introduction diff --git a/docs/background/plot_01_1D_basis_function.md b/docs/background/plot_01_1D_basis_function.md index 6c7d3a62..05edebe4 100644 --- a/docs/background/plot_01_1D_basis_function.md +++ b/docs/background/plot_01_1D_basis_function.md @@ -15,6 +15,29 @@ kernelspec: :tags: [hide-input] %matplotlib inline +import warnings + +# Ignore the first specific warning +warnings.filterwarnings( + "ignore", + message="plotting functions contained within `_documentation_utils` are intended for nemos's documentation.", + category=UserWarning, +) + +# Ignore the second specific warning +warnings.filterwarnings( + "ignore", + message="Ignoring cached namespace 'core'", + category=UserWarning, +) + +warnings.filterwarnings( + "ignore", + message=( + "invalid value encountered in div " + ), + category=RuntimeWarning, +) ``` (simple_basis_function)= diff --git a/docs/background/plot_02_ND_basis_function.md b/docs/background/plot_02_ND_basis_function.md index 8e62d7f6..84bbcdeb 100644 --- a/docs/background/plot_02_ND_basis_function.md +++ b/docs/background/plot_02_ND_basis_function.md @@ -15,6 +15,29 @@ kernelspec: :tags: [hide-input] %matplotlib inline +import warnings + +# Ignore the first specific warning +warnings.filterwarnings( + "ignore", + message="plotting functions contained within `_documentation_utils` are intended for nemos's documentation.", + category=UserWarning, +) + +# Ignore the second specific warning +warnings.filterwarnings( + "ignore", + message="Ignoring cached namespace 'core'", + category=UserWarning, +) + +warnings.filterwarnings( + "ignore", + message=( + "invalid value encountered in div " + ), + category=RuntimeWarning, +) ``` (composing_basis_function)= diff --git a/docs/background/plot_03_1D_convolution.md b/docs/background/plot_03_1D_convolution.md index f2a07688..04faf528 100644 --- a/docs/background/plot_03_1D_convolution.md +++ b/docs/background/plot_03_1D_convolution.md @@ -15,6 +15,29 @@ kernelspec: :tags: [hide-input] %matplotlib inline +import warnings + +# Ignore the first specific warning +warnings.filterwarnings( + "ignore", + message="plotting functions contained within `_documentation_utils` are intended for nemos's documentation.", + category=UserWarning, +) + +# Ignore the second specific warning +warnings.filterwarnings( + "ignore", + message="Ignoring cached namespace 'core'", + category=UserWarning, +) + +warnings.filterwarnings( + "ignore", + message=( + "invalid value encountered in div " + ), + category=RuntimeWarning, +) ``` (convolution_background)= diff --git a/docs/how_to_guide/plot_02_glm_demo.md b/docs/how_to_guide/plot_02_glm_demo.md index 72bb28fa..bdad8fc1 100644 --- a/docs/how_to_guide/plot_02_glm_demo.md +++ b/docs/how_to_guide/plot_02_glm_demo.md @@ -15,6 +15,29 @@ kernelspec: :tags: [hide-input] %matplotlib inline +import warnings + +# Ignore the first specific warning +warnings.filterwarnings( + "ignore", + message="plotting functions contained within `_documentation_utils` are intended for nemos's documentation.", + category=UserWarning, +) + +# Ignore the second specific warning +warnings.filterwarnings( + "ignore", + message="Ignoring cached namespace 'core'", + category=UserWarning, +) + +warnings.filterwarnings( + "ignore", + message=( + "invalid value encountered in div " + ), + category=RuntimeWarning, +) ``` diff --git a/docs/how_to_guide/plot_03_population_glm.md b/docs/how_to_guide/plot_03_population_glm.md index 827da40e..1239fed8 100644 --- a/docs/how_to_guide/plot_03_population_glm.md +++ b/docs/how_to_guide/plot_03_population_glm.md @@ -15,6 +15,29 @@ kernelspec: :tags: [hide-input] %matplotlib inline +import warnings + +# Ignore the first specific warning +warnings.filterwarnings( + "ignore", + message="plotting functions contained within `_documentation_utils` are intended for nemos's documentation.", + category=UserWarning, +) + +# Ignore the second specific warning +warnings.filterwarnings( + "ignore", + message="Ignoring cached namespace 'core'", + category=UserWarning, +) + +warnings.filterwarnings( + "ignore", + message=( + "invalid value encountered in div " + ), + category=RuntimeWarning, +) ``` diff --git a/docs/how_to_guide/plot_04_batch_glm.md b/docs/how_to_guide/plot_04_batch_glm.md index 7043d745..63342acc 100644 --- a/docs/how_to_guide/plot_04_batch_glm.md +++ b/docs/how_to_guide/plot_04_batch_glm.md @@ -15,6 +15,29 @@ kernelspec: :tags: [hide-input] %matplotlib inline +import warnings + +# Ignore the first specific warning +warnings.filterwarnings( + "ignore", + message="plotting functions contained within `_documentation_utils` are intended for nemos's documentation.", + category=UserWarning, +) + +# Ignore the second specific warning +warnings.filterwarnings( + "ignore", + message="Ignoring cached namespace 'core'", + category=UserWarning, +) + +warnings.filterwarnings( + "ignore", + message=( + "invalid value encountered in div " + ), + category=RuntimeWarning, +) ``` diff --git a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md index 4a91b4f8..170ab68b 100644 --- a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md +++ b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md @@ -15,6 +15,29 @@ kernelspec: :tags: [hide-input] %matplotlib inline +import warnings + +# Ignore the first specific warning +warnings.filterwarnings( + "ignore", + message="plotting functions contained within `_documentation_utils` are intended for nemos's documentation.", + category=UserWarning, +) + +# Ignore the second specific warning +warnings.filterwarnings( + "ignore", + message="Ignoring cached namespace 'core'", + category=UserWarning, +) + +warnings.filterwarnings( + "ignore", + message=( + "invalid value encountered in div " + ), + category=RuntimeWarning, +) ``` (sklearn-how-to)= diff --git a/docs/how_to_guide/plot_06_glm_pytree.md b/docs/how_to_guide/plot_06_glm_pytree.md index c613b605..58146377 100644 --- a/docs/how_to_guide/plot_06_glm_pytree.md +++ b/docs/how_to_guide/plot_06_glm_pytree.md @@ -15,6 +15,29 @@ kernelspec: :tags: [hide-input] %matplotlib inline +import warnings + +# Ignore the first specific warning +warnings.filterwarnings( + "ignore", + message="plotting functions contained within `_documentation_utils` are intended for nemos's documentation.", + category=UserWarning, +) + +# Ignore the second specific warning +warnings.filterwarnings( + "ignore", + message="Ignoring cached namespace 'core'", + category=UserWarning, +) + +warnings.filterwarnings( + "ignore", + message=( + "invalid value encountered in div " + ), + category=RuntimeWarning, +) ``` # FeaturePytree example @@ -164,6 +187,8 @@ print(jax.tree_util.tree_map(jnp.mean, example_pytree)) print(jax.tree_util.tree_map(lambda x: x.shape, example_pytree)) import matplotlib.pyplot as plt import pynapple as nap + +nap.nap_config.suppress_conversion_warnings = True ``` ## FeaturePytrees and GLM diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md index 50890639..6f82cbd9 100644 --- a/docs/tutorials/plot_01_current_injection.md +++ b/docs/tutorials/plot_01_current_injection.md @@ -15,6 +15,29 @@ kernelspec: :tags: [hide-input] %matplotlib inline +import warnings + +# Ignore the first specific warning +warnings.filterwarnings( + "ignore", + message="plotting functions contained within `_documentation_utils` are intended for nemos's documentation.", + category=UserWarning, +) + +# Ignore the second specific warning +warnings.filterwarnings( + "ignore", + message="Ignoring cached namespace 'core'", + category=UserWarning, +) + +warnings.filterwarnings( + "ignore", + message=( + "invalid value encountered in div " + ), + category=RuntimeWarning, +) ``` # Fit injected current diff --git a/docs/tutorials/plot_02_head_direction.md b/docs/tutorials/plot_02_head_direction.md index d1c0291b..b6918bde 100644 --- a/docs/tutorials/plot_02_head_direction.md +++ b/docs/tutorials/plot_02_head_direction.md @@ -15,6 +15,29 @@ kernelspec: :tags: [hide-input] %matplotlib inline +import warnings + +# Ignore the first specific warning +warnings.filterwarnings( + "ignore", + message="plotting functions contained within `_documentation_utils` are intended for nemos's documentation.", + category=UserWarning, +) + +# Ignore the second specific warning +warnings.filterwarnings( + "ignore", + message="Ignoring cached namespace 'core'", + category=UserWarning, +) + +warnings.filterwarnings( + "ignore", + message=( + "invalid value encountered in div " + ), + category=RuntimeWarning, +) ``` diff --git a/docs/tutorials/plot_03_grid_cells.md b/docs/tutorials/plot_03_grid_cells.md index 1ad3806a..55e9dfee 100644 --- a/docs/tutorials/plot_03_grid_cells.md +++ b/docs/tutorials/plot_03_grid_cells.md @@ -15,6 +15,29 @@ kernelspec: :tags: [hide-input] %matplotlib inline +import warnings + +# Ignore the first specific warning +warnings.filterwarnings( + "ignore", + message="plotting functions contained within `_documentation_utils` are intended for nemos's documentation.", + category=UserWarning, +) + +# Ignore the second specific warning +warnings.filterwarnings( + "ignore", + message="Ignoring cached namespace 'core'", + category=UserWarning, +) + +warnings.filterwarnings( + "ignore", + message=( + "invalid value encountered in div " + ), + category=RuntimeWarning, +) ``` diff --git a/docs/tutorials/plot_04_v1_cells.md b/docs/tutorials/plot_04_v1_cells.md index 8b1f60a5..d413a4be 100644 --- a/docs/tutorials/plot_04_v1_cells.md +++ b/docs/tutorials/plot_04_v1_cells.md @@ -15,6 +15,29 @@ kernelspec: :tags: [hide-input] %matplotlib inline +import warnings + +# Ignore the first specific warning +warnings.filterwarnings( + "ignore", + message="plotting functions contained within `_documentation_utils` are intended for nemos's documentation.", + category=UserWarning, +) + +# Ignore the second specific warning +warnings.filterwarnings( + "ignore", + message="Ignoring cached namespace 'core'", + category=UserWarning, +) + +warnings.filterwarnings( + "ignore", + message=( + "invalid value encountered in div " + ), + category=RuntimeWarning, +) ``` # Fit V1 cell diff --git a/docs/tutorials/plot_05_place_cells.md b/docs/tutorials/plot_05_place_cells.md index 55e08186..a8e80020 100644 --- a/docs/tutorials/plot_05_place_cells.md +++ b/docs/tutorials/plot_05_place_cells.md @@ -15,6 +15,29 @@ kernelspec: :tags: [hide-input] %matplotlib inline +import warnings + +# Ignore the first specific warning +warnings.filterwarnings( + "ignore", + message="plotting functions contained within `_documentation_utils` are intended for nemos's documentation.", + category=UserWarning, +) + +# Ignore the second specific warning +warnings.filterwarnings( + "ignore", + message="Ignoring cached namespace 'core'", + category=UserWarning, +) + +warnings.filterwarnings( + "ignore", + message=( + "invalid value encountered in div " + ), + category=RuntimeWarning, +) ``` diff --git a/docs/tutorials/plot_06_calcium_imaging.md b/docs/tutorials/plot_06_calcium_imaging.md index 66c9c451..c43091e3 100644 --- a/docs/tutorials/plot_06_calcium_imaging.md +++ b/docs/tutorials/plot_06_calcium_imaging.md @@ -15,6 +15,29 @@ kernelspec: :tags: [hide-input] %matplotlib inline +import warnings + +# Ignore the first specific warning +warnings.filterwarnings( + "ignore", + message="plotting functions contained within `_documentation_utils` are intended for nemos's documentation.", + category=UserWarning, +) + +# Ignore the second specific warning +warnings.filterwarnings( + "ignore", + message="Ignoring cached namespace 'core'", + category=UserWarning, +) + +warnings.filterwarnings( + "ignore", + message=( + "invalid value encountered in div " + ), + category=RuntimeWarning, +) ``` (tutorial-calcium-imaging)= From d91eafe7cf2f528e46b4eba7a327229bf0ff668b Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 17:19:27 -0500 Subject: [PATCH 069/107] added svgs for how to --- .../how_to_guide/plot_02_glm_demo.svg | 1853 +++++++++ .../how_to_guide/plot_03_population_glm.svg | 1324 ++++++ .../how_to_guide/plot_04_batch_glm.svg | 1298 ++++++ .../plot_05_sklearn_pipeline_cv_demo.svg | 2021 +++++++++ .../how_to_guide/plot_06_glm_pytree.svg | 3634 +++++++++++++++++ 5 files changed, 10130 insertions(+) create mode 100644 docs/assets/thumbnails/how_to_guide/plot_02_glm_demo.svg create mode 100644 docs/assets/thumbnails/how_to_guide/plot_03_population_glm.svg create mode 100644 docs/assets/thumbnails/how_to_guide/plot_04_batch_glm.svg create mode 100644 docs/assets/thumbnails/how_to_guide/plot_05_sklearn_pipeline_cv_demo.svg create mode 100644 docs/assets/thumbnails/how_to_guide/plot_06_glm_pytree.svg diff --git a/docs/assets/thumbnails/how_to_guide/plot_02_glm_demo.svg b/docs/assets/thumbnails/how_to_guide/plot_02_glm_demo.svg new file mode 100644 index 00000000..49b41efd --- /dev/null +++ b/docs/assets/thumbnails/how_to_guide/plot_02_glm_demo.svg @@ -0,0 +1,1853 @@ + + + + + + + + 2024-11-21T17:18:47.348356 + image/svg+xml + + + Matplotlib v3.9.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/thumbnails/how_to_guide/plot_03_population_glm.svg b/docs/assets/thumbnails/how_to_guide/plot_03_population_glm.svg new file mode 100644 index 00000000..6a2c292b --- /dev/null +++ b/docs/assets/thumbnails/how_to_guide/plot_03_population_glm.svg @@ -0,0 +1,1324 @@ + + + + + + + + 2024-11-21T17:18:56.172876 + image/svg+xml + + + Matplotlib v3.9.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/thumbnails/how_to_guide/plot_04_batch_glm.svg b/docs/assets/thumbnails/how_to_guide/plot_04_batch_glm.svg new file mode 100644 index 00000000..8bf1d3b1 --- /dev/null +++ b/docs/assets/thumbnails/how_to_guide/plot_04_batch_glm.svg @@ -0,0 +1,1298 @@ + + + + + + + + 2024-11-21T17:19:07.097434 + image/svg+xml + + + Matplotlib v3.9.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/thumbnails/how_to_guide/plot_05_sklearn_pipeline_cv_demo.svg b/docs/assets/thumbnails/how_to_guide/plot_05_sklearn_pipeline_cv_demo.svg new file mode 100644 index 00000000..2742155c --- /dev/null +++ b/docs/assets/thumbnails/how_to_guide/plot_05_sklearn_pipeline_cv_demo.svg @@ -0,0 +1,2021 @@ + + + + + + + + 2024-11-21T17:16:29.632122 + image/svg+xml + + + Matplotlib v3.9.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/thumbnails/how_to_guide/plot_06_glm_pytree.svg b/docs/assets/thumbnails/how_to_guide/plot_06_glm_pytree.svg new file mode 100644 index 00000000..807e558a --- /dev/null +++ b/docs/assets/thumbnails/how_to_guide/plot_06_glm_pytree.svg @@ -0,0 +1,3634 @@ + + + + + + + + 2024-11-21T17:14:41.001984 + image/svg+xml + + + Matplotlib v3.9.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 9bfa0deb03fbeefd825a346702d1c8a5ae3f170b Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 17:29:27 -0500 Subject: [PATCH 070/107] modified svg --- .../background/plot_01_1D_basis_function.svg | 52 +- .../background/plot_02_ND_basis_function.svg | 398 +- .../background/plot_03_1D_convolution.svg | 692 ++-- .../how_to_guide/plot_02_glm_demo.svg | 138 +- .../how_to_guide/plot_03_population_glm.svg | 78 +- .../how_to_guide/plot_04_batch_glm.svg | 34 +- .../plot_05_sklearn_pipeline_cv_demo.svg | 2345 ++++++------ .../how_to_guide/plot_06_glm_pytree.svg | 236 +- .../tutorials/plot_01_current_injection.svg | 304 +- .../tutorials/plot_02_head_direction.svg | 3194 ++++++++--------- .../tutorials/plot_03_grid_cells.svg | 96 +- .../thumbnails/tutorials/plot_04_v1_cells.svg | 36 +- .../tutorials/plot_05_place_cells.svg | 458 +-- .../tutorials/plot_06_calcium_imaging.svg | 46 +- docs/how_to_guide/plot_02_glm_demo.md | 2 + 15 files changed, 4060 insertions(+), 4049 deletions(-) diff --git a/docs/assets/thumbnails/background/plot_01_1D_basis_function.svg b/docs/assets/thumbnails/background/plot_01_1D_basis_function.svg index 051f1085..d37e76f0 100644 --- a/docs/assets/thumbnails/background/plot_01_1D_basis_function.svg +++ b/docs/assets/thumbnails/background/plot_01_1D_basis_function.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:18:21.319844 + 2024-11-21T17:23:22.546960 image/svg+xml @@ -41,12 +41,12 @@ z - - + @@ -82,7 +82,7 @@ z - + @@ -123,7 +123,7 @@ z - + @@ -159,7 +159,7 @@ z - + @@ -206,7 +206,7 @@ z - + @@ -262,7 +262,7 @@ z - + @@ -296,12 +296,12 @@ z - - + @@ -325,7 +325,7 @@ z - + @@ -340,7 +340,7 @@ z - + @@ -355,7 +355,7 @@ z - + @@ -370,7 +370,7 @@ z - + @@ -385,7 +385,7 @@ z - + @@ -428,7 +428,7 @@ L 117.336436 295.430344 L 120.258327 295.488 L 398.487273 295.488 L 398.487273 295.488 -" clip-path="url(#paa183a60a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5458b38fce)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5458b38fce)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5458b38fce)" style="fill: none; stroke: #2ca02c; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5458b38fce)" style="fill: none; stroke: #d62728; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5458b38fce)" style="fill: none; stroke: #9467bd; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5458b38fce)" style="fill: none; stroke: #8c564b; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5458b38fce)" style="fill: none; stroke: #e377c2; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5458b38fce)" style="fill: none; stroke: #7f7f7f; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5458b38fce)" style="fill: none; stroke: #bcbd22; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5458b38fce)" style="fill: none; stroke: #17becf; stroke-width: 1.5; stroke-linecap: square"/> + diff --git a/docs/assets/thumbnails/background/plot_02_ND_basis_function.svg b/docs/assets/thumbnails/background/plot_02_ND_basis_function.svg index 5f358436..ce171a58 100644 --- a/docs/assets/thumbnails/background/plot_02_ND_basis_function.svg +++ b/docs/assets/thumbnails/background/plot_02_ND_basis_function.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:18:28.466348 + 2024-11-21T17:23:29.898877 image/svg+xml @@ -41,12 +41,12 @@ z - - + @@ -92,7 +92,7 @@ z - + @@ -159,7 +159,7 @@ z - + @@ -175,7 +175,7 @@ z - + @@ -203,7 +203,7 @@ z - + @@ -237,12 +237,12 @@ z - - + @@ -255,7 +255,7 @@ L -3.5 0 - + @@ -269,7 +269,7 @@ L -3.5 0 - + @@ -317,7 +317,7 @@ L 47.556612 105.460908 L 47.971858 105.561818 L 175.591026 105.561818 L 175.591026 105.561818 -" clip-path="url(#p7c2b780cd0)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p72c0ed5623)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p72c0ed5623)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p72c0ed5623)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p72c0ed5623)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p72c0ed5623)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p72c0ed5623)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p72c0ed5623)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p72c0ed5623)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p72c0ed5623)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p72c0ed5623)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p72c0ed5623)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p72c0ed5623)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p72c0ed5623)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p72c0ed5623)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p72c0ed5623)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p72c0ed5623)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> - + @@ -921,7 +921,7 @@ z - + @@ -937,7 +937,7 @@ z - + @@ -953,7 +953,7 @@ z - + @@ -969,7 +969,7 @@ z - + @@ -987,7 +987,7 @@ z - + @@ -1002,7 +1002,7 @@ z - + @@ -1017,7 +1017,7 @@ z - + @@ -1039,7 +1039,7 @@ L 230.460819 105.210754 L 230.599234 105.561818 L 366.938584 105.561818 L 366.938584 105.561818 -" clip-path="url(#p0b3a89a65f)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d5a34994d)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d5a34994d)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d5a34994d)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d5a34994d)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d5a34994d)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d5a34994d)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d5a34994d)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d5a34994d)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d5a34994d)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d5a34994d)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d5a34994d)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d5a34994d)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d5a34994d)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d5a34994d)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d5a34994d)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1d9701bb63)" style="fill: #eaf3fb"/> +" clip-path="url(#p1d9701bb63)" style="fill: #d2e3f3"/> +" clip-path="url(#p1d9701bb63)" style="fill: #b2d2e8"/> +" clip-path="url(#p1d9701bb63)" style="fill: #84bcdb"/> +" clip-path="url(#p1d9701bb63)" style="fill: #56a0ce"/> +" clip-path="url(#p1d9701bb63)" style="fill: #3181bd"/> +" clip-path="url(#p1d9701bb63)" style="fill: #1460a8"/> +" clip-path="url(#p1d9701bb63)" style="fill: #084082"/> - + @@ -2506,7 +2506,7 @@ z - + @@ -2521,7 +2521,7 @@ z - + @@ -2659,7 +2659,7 @@ z - + @@ -2675,7 +2675,7 @@ z - + @@ -2691,7 +2691,7 @@ z - + @@ -2707,7 +2707,7 @@ z - + @@ -2723,7 +2723,7 @@ z - + @@ -2873,7 +2873,7 @@ z - + @@ -2889,7 +2889,7 @@ z - + @@ -2905,7 +2905,7 @@ z - + @@ -2921,7 +2921,7 @@ z - + @@ -2937,7 +2937,7 @@ z - + @@ -2955,7 +2955,7 @@ z - + @@ -2968,7 +2968,7 @@ z - + @@ -2982,7 +2982,7 @@ z - + @@ -3009,7 +3009,7 @@ L 47.556612 245.860908 L 47.971858 245.961818 L 175.591026 245.961818 L 175.591026 245.961818 -" clip-path="url(#p5450aec2fb)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe5f2e0e638)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe5f2e0e638)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe5f2e0e638)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe5f2e0e638)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe5f2e0e638)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe5f2e0e638)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe5f2e0e638)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe5f2e0e638)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe5f2e0e638)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe5f2e0e638)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe5f2e0e638)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe5f2e0e638)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe5f2e0e638)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe5f2e0e638)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe5f2e0e638)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe5f2e0e638)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> - + @@ -3552,7 +3552,7 @@ z - + @@ -3568,7 +3568,7 @@ z - + @@ -3584,7 +3584,7 @@ z - + @@ -3600,7 +3600,7 @@ z - + @@ -3618,7 +3618,7 @@ z - + @@ -3633,7 +3633,7 @@ z - + @@ -3648,7 +3648,7 @@ z - + @@ -3670,7 +3670,7 @@ L 230.460819 245.610754 L 230.599234 245.961818 L 366.938584 245.961818 L 366.938584 245.961818 -" clip-path="url(#p48ba903a81)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p862d7c8e0e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p862d7c8e0e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p862d7c8e0e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p862d7c8e0e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p862d7c8e0e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p862d7c8e0e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p862d7c8e0e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p862d7c8e0e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p862d7c8e0e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p862d7c8e0e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p862d7c8e0e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p862d7c8e0e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p862d7c8e0e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p862d7c8e0e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p862d7c8e0e)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p00a0ca3a2f)" style="fill: #e9f2fa"/> +" clip-path="url(#p00a0ca3a2f)" style="fill: #cde0f1"/> +" clip-path="url(#p00a0ca3a2f)" style="fill: #a4cce3"/> +" clip-path="url(#p00a0ca3a2f)" style="fill: #6aaed6"/> +" clip-path="url(#p00a0ca3a2f)" style="fill: #3d8dc4"/> +" clip-path="url(#p00a0ca3a2f)" style="fill: #1967ad"/> +" clip-path="url(#p00a0ca3a2f)" style="fill: #084387"/> - + @@ -5420,7 +5420,7 @@ z - + @@ -5435,7 +5435,7 @@ z - + @@ -5464,7 +5464,7 @@ z - + @@ -5480,7 +5480,7 @@ z - + @@ -5496,7 +5496,7 @@ z - + @@ -5512,7 +5512,7 @@ z - + @@ -5528,7 +5528,7 @@ z - + @@ -5613,7 +5613,7 @@ z - + @@ -5629,7 +5629,7 @@ z - + @@ -5645,7 +5645,7 @@ z - + @@ -5661,7 +5661,7 @@ z - + @@ -5677,7 +5677,7 @@ z - + @@ -5707,7 +5707,7 @@ z - + @@ -5720,7 +5720,7 @@ z - + @@ -5734,7 +5734,7 @@ z - + @@ -5761,7 +5761,7 @@ L 47.556612 386.260908 L 47.971858 386.361818 L 175.591026 386.361818 L 175.591026 386.361818 -" clip-path="url(#paf9f9b9397)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ee9d45014)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ee9d45014)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ee9d45014)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ee9d45014)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ee9d45014)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ee9d45014)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ee9d45014)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ee9d45014)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ee9d45014)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ee9d45014)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ee9d45014)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ee9d45014)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ee9d45014)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ee9d45014)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ee9d45014)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ee9d45014)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> - + @@ -6302,7 +6302,7 @@ z - + @@ -6318,7 +6318,7 @@ z - + @@ -6334,7 +6334,7 @@ z - + @@ -6350,7 +6350,7 @@ z - + @@ -6380,7 +6380,7 @@ z - + @@ -6395,7 +6395,7 @@ z - + @@ -6410,7 +6410,7 @@ z - + @@ -6432,7 +6432,7 @@ L 230.460819 386.010754 L 230.599234 386.361818 L 366.938584 386.361818 L 366.938584 386.361818 -" clip-path="url(#p628da7ad66)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p283a51e257)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p283a51e257)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p283a51e257)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p283a51e257)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p283a51e257)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p283a51e257)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p283a51e257)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p283a51e257)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p283a51e257)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p283a51e257)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p283a51e257)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p283a51e257)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p283a51e257)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p283a51e257)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p283a51e257)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0e4ef3954d)" style="fill: #e9f2fa"/> +" clip-path="url(#p0e4ef3954d)" style="fill: #cde0f1"/> +" clip-path="url(#p0e4ef3954d)" style="fill: #a4cce3"/> +" clip-path="url(#p0e4ef3954d)" style="fill: #6aaed6"/> +" clip-path="url(#p0e4ef3954d)" style="fill: #3d8dc4"/> +" clip-path="url(#p0e4ef3954d)" style="fill: #1967ad"/> +" clip-path="url(#p0e4ef3954d)" style="fill: #084387"/> - + @@ -8403,7 +8403,7 @@ z - + @@ -8418,7 +8418,7 @@ z - + @@ -8447,7 +8447,7 @@ z - + @@ -8463,7 +8463,7 @@ z - + @@ -8479,7 +8479,7 @@ z - + @@ -8495,7 +8495,7 @@ z - + @@ -8511,7 +8511,7 @@ z - + @@ -8587,31 +8587,31 @@ L 529.607558 309.12 - + - + - + - + - + - + - + - + - + diff --git a/docs/assets/thumbnails/background/plot_03_1D_convolution.svg b/docs/assets/thumbnails/background/plot_03_1D_convolution.svg index 1bf9e6ff..f57c7f32 100644 --- a/docs/assets/thumbnails/background/plot_03_1D_convolution.svg +++ b/docs/assets/thumbnails/background/plot_03_1D_convolution.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:18:34.739430 + 2024-11-21T17:23:36.350383 image/svg+xml @@ -43,18 +43,18 @@ L 97.982668 83.350909 L 97.982668 29.569091 L 63.579545 29.569091 z -" clip-path="url(#pc06ca2decf)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> +" clip-path="url(#pd40d1c7e12)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> - - + @@ -90,7 +90,7 @@ z - + @@ -130,7 +130,7 @@ z - + @@ -165,7 +165,7 @@ z - + @@ -211,7 +211,7 @@ z - + @@ -266,7 +266,7 @@ z - + @@ -299,12 +299,12 @@ z - - + @@ -361,7 +361,7 @@ z - + @@ -376,7 +376,7 @@ z - + @@ -519,304 +519,304 @@ z +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd40d1c7e12)" style="fill: none; stroke: #2ca02c; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd4df97c688)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> - + @@ -1291,7 +1291,7 @@ z - + @@ -1305,7 +1305,7 @@ z - + @@ -1319,7 +1319,7 @@ z - + @@ -1333,7 +1333,7 @@ z - + @@ -1347,7 +1347,7 @@ z - + @@ -1364,7 +1364,7 @@ z - + @@ -1380,7 +1380,7 @@ z - + @@ -1395,7 +1395,7 @@ z - + @@ -1450,304 +1450,304 @@ z +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd4df97c688)" style="fill: none; stroke: #2ca02c; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> - + @@ -2091,7 +2091,7 @@ z - + @@ -2105,7 +2105,7 @@ z - + @@ -2119,7 +2119,7 @@ z - + @@ -2133,7 +2133,7 @@ z - + @@ -2147,7 +2147,7 @@ z - + @@ -2164,7 +2164,7 @@ z - + @@ -2180,7 +2180,7 @@ z - + @@ -2195,7 +2195,7 @@ z - + @@ -2223,304 +2223,304 @@ z +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p78dfb9b4e3)" style="fill: none; stroke: #2ca02c; stroke-width: 1.5; stroke-linecap: square"/> + - + - + diff --git a/docs/assets/thumbnails/how_to_guide/plot_02_glm_demo.svg b/docs/assets/thumbnails/how_to_guide/plot_02_glm_demo.svg index 49b41efd..07e8fe75 100644 --- a/docs/assets/thumbnails/how_to_guide/plot_02_glm_demo.svg +++ b/docs/assets/thumbnails/how_to_guide/plot_02_glm_demo.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:18:47.348356 + 2024-11-21T17:28:01.655472 image/svg+xml @@ -43,18 +43,18 @@ L 236.32249 307.584 L 236.32249 24.486128 L 138.828632 24.486128 z -" clip-path="url(#p70adb62ecd)" style="fill: #808080; opacity: 0.2; stroke: #808080; stroke-linejoin: miter"/> +" clip-path="url(#p32270c59a3)" style="fill: #808080; opacity: 0.2; stroke: #808080; stroke-linejoin: miter"/> - - + @@ -90,7 +90,7 @@ z - + @@ -131,7 +131,7 @@ z - + @@ -167,7 +167,7 @@ z - + @@ -214,7 +214,7 @@ z - + @@ -270,7 +270,7 @@ z - + @@ -304,12 +304,12 @@ z - - + @@ -334,7 +334,7 @@ z - + @@ -350,7 +350,7 @@ z - + @@ -366,7 +366,7 @@ z - + @@ -382,7 +382,7 @@ z - + @@ -398,7 +398,7 @@ z - + @@ -414,7 +414,7 @@ z - + @@ -1021,7 +1021,7 @@ L 396.862375 263.006827 L 397.512334 260.237355 L 398.487273 254.514111 L 398.487273 254.514111 -" clip-path="url(#p70adb62ecd)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linecap: square"/> + diff --git a/docs/assets/thumbnails/how_to_guide/plot_03_population_glm.svg b/docs/assets/thumbnails/how_to_guide/plot_03_population_glm.svg index 6a2c292b..ec8d60bc 100644 --- a/docs/assets/thumbnails/how_to_guide/plot_03_population_glm.svg +++ b/docs/assets/thumbnails/how_to_guide/plot_03_population_glm.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:18:56.172876 + 2024-11-21T17:24:02.443975 image/svg+xml @@ -43,7 +43,7 @@ L 72.543957 188.12 L 72.543957 65.863003 L 55.123636 65.863003 z -" clip-path="url(#p1d928c94fc)" style="fill: #1f77b4"/> +" clip-path="url(#p169d812c27)" style="fill: #1f77b4"/> +" clip-path="url(#p169d812c27)" style="fill: #1f77b4"/> +" clip-path="url(#p169d812c27)" style="fill: #ff7f0e"/> +" clip-path="url(#p169d812c27)" style="fill: #ff7f0e"/> +" clip-path="url(#p169d812c27)" style="fill: #2ca02c"/> +" clip-path="url(#p169d812c27)" style="fill: #2ca02c"/> - - + @@ -278,7 +278,7 @@ z - + @@ -317,12 +317,12 @@ z - - + @@ -346,7 +346,7 @@ z - + @@ -361,7 +361,7 @@ z - + @@ -402,7 +402,7 @@ z - + @@ -451,7 +451,7 @@ z - + @@ -487,7 +487,7 @@ z - + @@ -529,7 +529,7 @@ z - + @@ -576,7 +576,7 @@ z - + @@ -603,7 +603,7 @@ z - + @@ -798,7 +798,7 @@ L 283.143957 188.12 L 283.143957 134.233231 L 265.723636 134.233231 z -" clip-path="url(#p2e12ebf69d)" style="fill: #1f77b4"/> +" clip-path="url(#p6aa75607ec)" style="fill: #1f77b4"/> +" clip-path="url(#p6aa75607ec)" style="fill: #1f77b4"/> +" clip-path="url(#p6aa75607ec)" style="fill: #ff7f0e"/> +" clip-path="url(#p6aa75607ec)" style="fill: #ff7f0e"/> +" clip-path="url(#p6aa75607ec)" style="fill: #2ca02c"/> +" clip-path="url(#p6aa75607ec)" style="fill: #2ca02c"/> - + @@ -865,7 +865,7 @@ z - + @@ -888,7 +888,7 @@ z - + @@ -903,7 +903,7 @@ z - + @@ -918,7 +918,7 @@ z - + @@ -933,7 +933,7 @@ z - + @@ -948,7 +948,7 @@ z - + @@ -963,7 +963,7 @@ z - + @@ -978,7 +978,7 @@ z - + @@ -993,7 +993,7 @@ z - + @@ -1008,7 +1008,7 @@ z - + @@ -1314,10 +1314,10 @@ z - + - + diff --git a/docs/assets/thumbnails/how_to_guide/plot_04_batch_glm.svg b/docs/assets/thumbnails/how_to_guide/plot_04_batch_glm.svg index 8bf1d3b1..301b3979 100644 --- a/docs/assets/thumbnails/how_to_guide/plot_04_batch_glm.svg +++ b/docs/assets/thumbnails/how_to_guide/plot_04_batch_glm.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:19:07.097434 + 2024-11-21T17:24:13.265334 image/svg+xml @@ -41,12 +41,12 @@ z - - + @@ -82,7 +82,7 @@ z - + @@ -113,7 +113,7 @@ z - + @@ -154,7 +154,7 @@ z - + @@ -203,7 +203,7 @@ z - + @@ -239,7 +239,7 @@ z - + @@ -455,12 +455,12 @@ z - - + @@ -523,7 +523,7 @@ z - + @@ -540,7 +540,7 @@ z - + @@ -557,7 +557,7 @@ z - + @@ -574,7 +574,7 @@ z - + @@ -632,7 +632,7 @@ z - + @@ -1266,7 +1266,7 @@ L 397.186052 63.77007 L 397.836662 69.754119 L 398.487273 85.098222 L 398.487273 85.098222 -" clip-path="url(#p326d52184b)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p02d2a7eaf1)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> + diff --git a/docs/assets/thumbnails/how_to_guide/plot_05_sklearn_pipeline_cv_demo.svg b/docs/assets/thumbnails/how_to_guide/plot_05_sklearn_pipeline_cv_demo.svg index 2742155c..686d7693 100644 --- a/docs/assets/thumbnails/how_to_guide/plot_05_sklearn_pipeline_cv_demo.svg +++ b/docs/assets/thumbnails/how_to_guide/plot_05_sklearn_pipeline_cv_demo.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:16:29.632122 + 2024-11-21T17:24:39.724298 image/svg+xml @@ -39,7 +39,7 @@ z - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - + - + - + - + - + - + - + - + - + - + - + - - + @@ -1452,7 +1452,7 @@ L -3.5 0 - + @@ -1465,7 +1465,7 @@ L -3.5 0 - + @@ -1478,7 +1478,7 @@ L -3.5 0 - + @@ -1491,7 +1491,7 @@ L -3.5 0 - + @@ -1504,7 +1504,7 @@ L -3.5 0 - + @@ -1518,7 +1518,7 @@ L -3.5 0 - + @@ -1532,7 +1532,7 @@ L -3.5 0 - + @@ -1546,7 +1546,7 @@ L -3.5 0 - + @@ -1690,132 +1690,141 @@ z - + - - + - + - - + @@ -2014,7 +2023,7 @@ L 86.6 69.248562 - + diff --git a/docs/assets/thumbnails/how_to_guide/plot_06_glm_pytree.svg b/docs/assets/thumbnails/how_to_guide/plot_06_glm_pytree.svg index 807e558a..92535cf8 100644 --- a/docs/assets/thumbnails/how_to_guide/plot_06_glm_pytree.svg +++ b/docs/assets/thumbnails/how_to_guide/plot_06_glm_pytree.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:14:41.001984 + 2024-11-21T17:25:24.201685 image/svg+xml @@ -72,7 +72,7 @@ z +" clip-path="url(#pb66cd08c0d)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -132,7 +132,7 @@ z +" clip-path="url(#pb66cd08c0d)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -193,7 +193,7 @@ z +" clip-path="url(#pb66cd08c0d)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -240,7 +240,7 @@ z +" clip-path="url(#pb66cd08c0d)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -304,7 +304,7 @@ z +" clip-path="url(#pb66cd08c0d)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -361,7 +361,7 @@ z +" clip-path="url(#pb66cd08c0d)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -403,7 +403,7 @@ z +" clip-path="url(#pb66cd08c0d)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -431,7 +431,7 @@ z +" clip-path="url(#pb66cd08c0d)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -464,7 +464,7 @@ C 156.657633 164.879303 158.444777 164.523818 160.112095 163.833192 C 161.779414 163.142566 163.294481 162.130231 164.570591 160.854121 C 165.846701 159.57801 166.859037 158.062943 167.549663 156.395625 C 168.240288 154.728307 168.595773 152.941163 168.595773 151.136471 -" clip-path="url(#pf76aa3d850)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pb66cd08c0d)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -492,7 +492,7 @@ C 158.462326 178.622135 162.036613 177.911165 165.37125 176.529914 C 168.705886 175.148662 171.736021 173.123991 174.288241 170.57177 C 176.840461 168.01955 178.865133 164.989415 180.246384 161.654779 C 181.627636 158.320143 182.338606 154.745855 182.338606 151.136471 -" clip-path="url(#pf76aa3d850)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pb66cd08c0d)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -520,7 +520,7 @@ C 160.267018 192.364968 165.628449 191.298512 170.630404 189.226635 C 175.632358 187.154758 180.177561 184.117751 184.005891 180.28942 C 187.834221 176.46109 190.871228 171.915888 192.943106 166.913933 C 195.014983 161.911979 196.081438 156.550547 196.081438 151.136471 -" clip-path="url(#pf76aa3d850)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pb66cd08c0d)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -580,7 +580,7 @@ C 162.07171 206.1078 169.220285 204.68586 175.889558 201.923357 C 182.558831 199.160853 188.6191 195.111511 193.723541 190.00707 C 198.827981 184.90263 202.877324 178.84236 205.639827 172.173088 C 208.40233 165.503815 209.82427 158.355239 209.82427 151.136471 -" clip-path="url(#pf76aa3d850)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pb66cd08c0d)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -608,7 +608,7 @@ C 163.876402 219.850632 172.812121 218.073207 181.148712 214.620078 C 189.485303 211.166949 197.06064 206.105271 203.441191 199.72472 C 209.821741 193.34417 214.88342 185.768833 218.336549 177.432242 C 221.789678 169.095651 223.567103 160.159932 223.567103 151.136471 -" clip-path="url(#pf76aa3d850)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pb66cd08c0d)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -650,7 +650,7 @@ L 148.288171 145.22221 L 152.482337 149.766881 L 153.782349 150.788255 L 152.767815 150.91665 -" clip-path="url(#pf76aa3d850)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb66cd08c0d)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ec683f018)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -815,7 +815,7 @@ L 405.476471 151.136471 +" clip-path="url(#p7ec683f018)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -830,7 +830,7 @@ L 383.985 99.251471 +" clip-path="url(#p7ec683f018)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -845,7 +845,7 @@ L 332.1 77.76 +" clip-path="url(#p7ec683f018)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -861,7 +861,7 @@ L 280.215 99.251471 +" clip-path="url(#p7ec683f018)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -877,7 +877,7 @@ L 258.723529 151.136471 +" clip-path="url(#p7ec683f018)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -893,7 +893,7 @@ L 280.215 203.021471 +" clip-path="url(#p7ec683f018)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -909,7 +909,7 @@ L 332.1 224.512941 +" clip-path="url(#p7ec683f018)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -942,7 +942,7 @@ C 334.364064 168.377448 336.606114 167.931476 338.697836 167.065056 C 340.789559 166.198637 342.690277 164.928618 344.291212 163.327682 C 345.892147 161.726747 347.162166 159.82603 348.028586 157.734307 C 348.895006 155.642584 349.340977 153.400535 349.340977 151.136471 -" clip-path="url(#pf484354806)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p7ec683f018)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -970,7 +970,7 @@ C 336.628129 185.618425 341.112227 184.726482 345.295673 182.993642 C 349.479118 181.260802 353.280553 178.720765 356.482424 175.518894 C 359.684294 172.317024 362.224332 168.515589 363.957172 164.332143 C 365.690012 160.148698 366.581954 155.664599 366.581954 151.136471 -" clip-path="url(#pf484354806)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p7ec683f018)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -998,7 +998,7 @@ C 338.892193 202.859402 345.618341 201.521488 351.893509 198.922228 C 358.168677 196.322968 363.87083 192.512912 368.673635 187.710106 C 373.476441 182.9073 377.286498 177.205148 379.885758 170.929979 C 382.485017 164.654811 383.822931 157.928664 383.822931 151.136471 -" clip-path="url(#pf484354806)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p7ec683f018)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1026,7 +1026,7 @@ C 341.156257 220.100379 350.124454 218.316494 358.491345 214.850814 C 366.858236 211.385134 374.461106 206.305059 380.864847 199.901318 C 387.268588 193.497577 392.348664 185.894707 395.814343 177.527816 C 399.280023 169.160925 401.063908 160.192728 401.063908 151.136471 -" clip-path="url(#pf484354806)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p7ec683f018)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1067,7 +1067,7 @@ L 312.334109 133.329201 L 313.661039 140.483576 L 311.68481 144.496331 L 313.788829 149.206052 -" clip-path="url(#pf484354806)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ec683f018)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe0a664dfb9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1159,7 +1159,7 @@ L 582.723529 151.136471 +" clip-path="url(#pe0a664dfb9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1174,7 +1174,7 @@ L 561.232059 99.251471 +" clip-path="url(#pe0a664dfb9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1189,7 +1189,7 @@ L 509.347059 77.76 +" clip-path="url(#pe0a664dfb9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1205,7 +1205,7 @@ L 457.462059 99.251471 +" clip-path="url(#pe0a664dfb9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1221,7 +1221,7 @@ L 435.970588 151.136471 +" clip-path="url(#pe0a664dfb9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1237,7 +1237,7 @@ L 457.462059 203.021471 +" clip-path="url(#pe0a664dfb9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1253,7 +1253,7 @@ L 509.347059 224.512941 +" clip-path="url(#pe0a664dfb9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1286,7 +1286,7 @@ C 512.002703 171.359353 514.632525 170.836249 517.086021 169.819978 C 519.539516 168.803706 521.768972 167.314032 523.646796 165.436208 C 525.52462 163.558383 527.014295 161.328928 528.030566 158.875433 C 529.046837 156.421937 529.569941 153.792115 529.569941 151.136471 -" clip-path="url(#p1dccaafd43)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pe0a664dfb9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1314,7 +1314,7 @@ C 514.658348 191.582235 519.917991 190.536027 524.824983 188.503484 C 529.731974 186.470942 534.190884 183.491593 537.946533 179.735945 C 541.702182 175.980296 544.68153 171.521386 546.714073 166.614395 C 548.746615 161.707403 549.792823 156.44776 549.792823 151.136471 -" clip-path="url(#p1dccaafd43)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pe0a664dfb9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1343,7 +1343,7 @@ C 517.313992 211.805117 525.203458 210.235805 532.563945 207.186991 C 539.924432 204.138178 546.612797 199.669155 552.24627 194.035682 C 557.879743 188.402209 562.348766 181.713843 565.39758 174.353356 C 568.446393 166.99287 570.015705 159.103404 570.015705 151.136471 -" clip-path="url(#p1dccaafd43)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pe0a664dfb9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1385,7 +1385,7 @@ L 498.748434 141.588074 L 471.253761 129.128513 L 461.328848 135.518313 L 439.849835 143.809863 -" clip-path="url(#p1dccaafd43)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe0a664dfb9)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf120e43782)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1477,7 +1477,7 @@ L 228.229412 327.24 +" clip-path="url(#pf120e43782)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1492,7 +1492,7 @@ L 206.737941 275.355 +" clip-path="url(#pf120e43782)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1507,7 +1507,7 @@ L 154.852941 253.863529 +" clip-path="url(#pf120e43782)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1523,7 +1523,7 @@ L 102.967941 275.355 +" clip-path="url(#pf120e43782)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1539,7 +1539,7 @@ L 81.476471 327.24 +" clip-path="url(#pf120e43782)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1555,7 +1555,7 @@ L 102.967941 379.125 +" clip-path="url(#pf120e43782)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1571,7 +1571,7 @@ L 154.852941 400.616471 +" clip-path="url(#pf120e43782)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1604,7 +1604,7 @@ C 156.50052 339.786407 158.132079 339.46187 159.654243 338.831369 C 161.176408 338.200868 162.559577 337.276664 163.724591 336.11165 C 164.889605 334.946635 165.813809 333.563467 166.44431 332.041302 C 167.074811 330.519138 167.399349 328.887579 167.399349 327.24 -" clip-path="url(#p9a4b5f20d8)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pf120e43782)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1643,7 +1643,7 @@ C 158.148099 352.332815 161.411216 351.683741 164.455546 350.422738 C 167.499875 349.161736 170.266212 347.313328 172.596241 344.9833 C 174.92627 342.653271 176.774677 339.886934 178.035679 336.842605 C 179.296682 333.798275 179.945756 330.535158 179.945756 327.24 -" clip-path="url(#p9a4b5f20d8)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pf120e43782)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1673,7 +1673,7 @@ C 159.795679 364.879222 164.690354 363.905611 169.256848 362.014107 C 173.823342 360.122603 177.972847 357.349993 181.467891 353.854949 C 184.962934 350.359906 187.735545 346.210401 189.627048 341.643907 C 191.518552 337.077413 192.492164 332.182737 192.492164 327.24 -" clip-path="url(#p9a4b5f20d8)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pf120e43782)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1703,7 +1703,7 @@ C 161.443258 377.42563 167.969492 376.127481 174.05815 373.605476 C 180.146809 371.083471 185.679483 367.386657 190.33954 362.726599 C 194.999598 358.066542 198.696412 352.533868 201.218417 346.445209 C 203.740422 340.356551 205.038571 333.830317 205.038571 327.24 -" clip-path="url(#p9a4b5f20d8)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pf120e43782)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1733,7 +1733,7 @@ C 163.090837 389.972037 171.248629 388.349352 178.859453 385.196845 C 186.470276 382.044339 193.386118 377.423321 199.21119 371.598249 C 205.036262 365.773177 209.65728 358.857335 212.809786 351.246511 C 215.962293 343.635688 217.584979 335.477896 217.584979 327.24 -" clip-path="url(#p9a4b5f20d8)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pf120e43782)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1776,7 +1776,7 @@ L 143.208905 316.749783 L 135.807767 316.236873 L 136.868987 321.390631 L 144.383144 326.136242 -" clip-path="url(#p9a4b5f20d8)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf120e43782)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2480407013)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1868,7 +1868,7 @@ L 405.476471 327.24 +" clip-path="url(#p2480407013)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1883,7 +1883,7 @@ L 383.985 275.355 +" clip-path="url(#p2480407013)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1898,7 +1898,7 @@ L 332.1 253.863529 +" clip-path="url(#p2480407013)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1914,7 +1914,7 @@ L 280.215 275.355 +" clip-path="url(#p2480407013)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1930,7 +1930,7 @@ L 258.723529 327.24 +" clip-path="url(#p2480407013)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1946,7 +1946,7 @@ L 280.215 379.125 +" clip-path="url(#p2480407013)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1962,7 +1962,7 @@ L 332.1 400.616471 +" clip-path="url(#p2480407013)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1995,7 +1995,7 @@ C 333.870113 340.71951 335.623014 340.370837 337.258385 339.693444 C 338.893757 339.016051 340.379794 338.023112 341.631453 336.771453 C 342.883112 335.519794 343.876051 334.033757 344.553444 332.398385 C 345.230837 330.763014 345.57951 329.010113 345.57951 327.24 -" clip-path="url(#pd24434384e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p2480407013)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2023,7 +2023,7 @@ C 335.640226 354.199021 339.146028 353.501673 342.416771 352.146888 C 345.687513 350.792102 348.659588 348.806224 351.162906 346.302906 C 353.666224 343.799588 355.652102 340.827513 357.006888 337.556771 C 358.361673 334.286028 359.059021 330.780226 359.059021 327.24 -" clip-path="url(#pd24434384e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p2480407013)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2051,7 +2051,7 @@ C 337.410339 367.678531 342.669042 366.63251 347.575156 364.600331 C 352.48127 362.568152 356.939383 359.589337 360.69436 355.83436 C 364.449337 352.079383 367.428152 347.62127 369.460331 342.715156 C 371.49251 337.809042 372.538531 332.550339 372.538531 327.24 -" clip-path="url(#pd24434384e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p2480407013)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2079,7 +2079,7 @@ C 339.180452 381.158042 346.192056 379.763347 352.733541 377.053775 C 359.275026 374.344203 365.219177 370.372449 370.225813 365.365813 C 375.232449 360.359177 379.204203 354.415026 381.913775 347.873541 C 384.623347 341.332056 386.018042 334.320452 386.018042 327.24 -" clip-path="url(#pd24434384e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p2480407013)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2107,7 +2107,7 @@ C 340.950565 394.637552 349.71507 392.894184 357.891927 389.507219 C 366.068783 386.120254 373.498971 381.155561 379.757266 374.897266 C 386.015561 368.638971 390.980254 361.208783 394.367219 353.031927 C 397.754184 344.85507 399.497552 336.090565 399.497552 327.24 -" clip-path="url(#pd24434384e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p2480407013)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2148,7 +2148,7 @@ L 317.38232 313.980709 L 318.148906 319.179919 L 321.179176 323.687949 L 323.919303 326.377566 -" clip-path="url(#pd24434384e)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2480407013)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd02bf96ddd)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2240,7 +2240,7 @@ L 582.723529 327.24 +" clip-path="url(#pd02bf96ddd)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2255,7 +2255,7 @@ L 561.232059 275.355 +" clip-path="url(#pd02bf96ddd)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2270,7 +2270,7 @@ L 509.347059 253.863529 +" clip-path="url(#pd02bf96ddd)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2286,7 +2286,7 @@ L 457.462059 275.355 +" clip-path="url(#pd02bf96ddd)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2302,7 +2302,7 @@ L 435.970588 327.24 +" clip-path="url(#pd02bf96ddd)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2318,7 +2318,7 @@ L 457.462059 379.125 +" clip-path="url(#pd02bf96ddd)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2334,7 +2334,7 @@ L 509.347059 400.616471 +" clip-path="url(#pd02bf96ddd)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2367,7 +2367,7 @@ C 511.480087 343.483132 513.592375 343.062972 515.563036 342.246697 C 517.533698 341.430423 519.324409 340.233908 520.832688 338.725629 C 522.340967 337.21735 523.537481 335.426639 524.353756 333.455978 C 525.170031 331.485316 525.590191 329.373029 525.590191 327.24 -" clip-path="url(#pbf3d060b5b)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pd02bf96ddd)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2397,7 +2397,7 @@ C 513.613116 359.726264 517.837691 358.885944 521.779014 357.253395 C 525.720337 355.620845 529.301759 353.227816 532.318317 350.211258 C 535.334874 347.1947 537.727904 343.613278 539.360453 339.671955 C 540.993003 335.730632 541.833323 331.506057 541.833323 327.24 -" clip-path="url(#pbf3d060b5b)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pd02bf96ddd)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2427,7 +2427,7 @@ C 515.746145 375.969396 522.083007 374.708916 527.994991 372.260092 C 533.906976 369.811268 539.279109 366.221724 543.803945 361.696887 C 548.328782 357.17205 551.918327 351.799917 554.367151 345.887933 C 556.815975 339.975948 558.076455 333.639086 558.076455 327.24 -" clip-path="url(#pbf3d060b5b)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pd02bf96ddd)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2457,7 +2457,7 @@ C 517.879173 392.212528 526.328323 390.531888 534.210969 387.266789 C 542.093615 384.00169 549.256458 379.215631 555.289574 373.182515 C 561.32269 367.1494 566.108749 359.986556 569.373848 352.10391 C 572.638947 344.221264 574.319587 335.772114 574.319587 327.24 -" clip-path="url(#pbf3d060b5b)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pd02bf96ddd)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2500,7 +2500,7 @@ L 483.631083 304.072245 L 481.328057 311.052349 L 466.830606 313.411317 L 463.754108 322.433453 -" clip-path="url(#pbf3d060b5b)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd02bf96ddd)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p374c4e0d24)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2592,7 +2592,7 @@ L 228.229412 503.343529 +" clip-path="url(#p374c4e0d24)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2607,7 +2607,7 @@ L 206.737941 451.458529 +" clip-path="url(#p374c4e0d24)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2622,7 +2622,7 @@ L 154.852941 429.967059 +" clip-path="url(#p374c4e0d24)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2638,7 +2638,7 @@ L 102.967941 451.458529 +" clip-path="url(#p374c4e0d24)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2654,7 +2654,7 @@ L 81.476471 503.343529 +" clip-path="url(#p374c4e0d24)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2670,7 +2670,7 @@ L 102.967941 555.228529 +" clip-path="url(#p374c4e0d24)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2686,7 +2686,7 @@ L 154.852941 576.72 +" clip-path="url(#p374c4e0d24)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2719,7 +2719,7 @@ C 156.40566 515.167571 157.943281 514.861719 159.377806 514.267519 C 160.812331 513.673319 162.115863 512.802327 163.213801 511.704389 C 164.311739 510.606451 165.182731 509.302919 165.776931 507.868394 C 166.371131 506.433869 166.676982 504.896248 166.676982 503.343529 -" clip-path="url(#pc5c762780a)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p374c4e0d24)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2750,7 +2750,7 @@ C 157.958379 526.991612 161.03362 526.379908 163.902671 525.191509 C 166.771721 524.003109 169.378785 522.261125 171.574661 520.065249 C 173.770537 517.869373 175.512521 515.262309 176.700921 512.393259 C 177.88932 509.524208 178.501024 506.448967 178.501024 503.343529 -" clip-path="url(#pc5c762780a)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p374c4e0d24)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2781,7 +2781,7 @@ C 159.511098 538.815653 164.12396 537.898098 168.427535 536.115499 C 172.731111 534.332899 176.641706 531.719923 179.935521 528.426109 C 183.229335 525.132295 185.842311 521.221699 187.62491 516.918124 C 189.40751 512.614548 190.325065 508.001686 190.325065 503.343529 -" clip-path="url(#pc5c762780a)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p374c4e0d24)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2812,7 +2812,7 @@ C 161.063817 550.639695 167.214299 549.416288 172.9524 547.039488 C 178.690501 544.662689 183.904628 541.178721 188.29638 536.786969 C 192.688132 532.395216 196.172101 527.181089 198.5489 521.442988 C 200.925699 515.704887 202.149106 509.554405 202.149106 503.343529 -" clip-path="url(#pc5c762780a)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p374c4e0d24)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2843,7 +2843,7 @@ C 162.616536 562.463736 170.304639 560.934477 177.477265 557.963478 C 184.649891 554.992479 191.16755 550.637519 196.65724 545.147828 C 202.14693 539.658138 206.501891 533.140479 209.47289 525.967853 C 212.443889 518.795227 213.973148 511.107124 213.973148 503.343529 -" clip-path="url(#pc5c762780a)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p374c4e0d24)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2874,7 +2874,7 @@ C 164.169254 574.287777 173.394978 572.452667 182.002129 568.887468 C 190.609281 565.322269 198.430472 560.096316 205.0181 553.508688 C 211.605728 546.92106 216.831681 539.099869 220.39688 530.492718 C 223.962078 521.885567 225.797189 512.659843 225.797189 503.343529 -" clip-path="url(#pc5c762780a)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p374c4e0d24)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2918,7 +2918,7 @@ L 153.561927 502.180443 L 154.852941 503.343529 L 153.379157 502.864174 L 154.852941 503.343529 -" clip-path="url(#pc5c762780a)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p374c4e0d24)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8353e7c1e6)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3010,7 +3010,7 @@ L 405.476471 503.343529 +" clip-path="url(#p8353e7c1e6)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3025,7 +3025,7 @@ L 383.985 451.458529 +" clip-path="url(#p8353e7c1e6)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3040,7 +3040,7 @@ L 332.1 429.967059 +" clip-path="url(#p8353e7c1e6)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3056,7 +3056,7 @@ L 280.215 451.458529 +" clip-path="url(#p8353e7c1e6)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3072,7 +3072,7 @@ L 258.723529 503.343529 +" clip-path="url(#p8353e7c1e6)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3088,7 +3088,7 @@ L 280.215 555.228529 +" clip-path="url(#p8353e7c1e6)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3104,7 +3104,7 @@ L 332.1 576.72 +" clip-path="url(#p8353e7c1e6)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3137,7 +3137,7 @@ C 333.818737 516.431807 335.520761 516.093253 337.108667 515.435521 C 338.696573 514.777789 340.139479 513.813669 341.35481 512.598339 C 342.57014 511.383009 343.534259 509.940102 344.191991 508.352196 C 344.849724 506.764291 345.188277 505.062266 345.188277 503.343529 -" clip-path="url(#p3dcb02ba35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p8353e7c1e6)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3165,7 +3165,7 @@ C 335.537474 529.520084 338.941522 528.842977 342.117334 527.527512 C 345.293145 526.212048 348.178958 524.28381 350.609619 521.853149 C 353.04028 519.422488 354.968519 516.536675 356.283983 513.360863 C 357.599447 510.185052 358.276554 506.781003 358.276554 503.343529 -" clip-path="url(#p3dcb02ba35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p8353e7c1e6)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3193,7 +3193,7 @@ C 337.25621 542.608361 342.362283 541.5927 347.126001 539.619504 C 351.889718 537.646307 356.218437 534.75395 359.864429 531.107958 C 363.51042 527.461967 366.402778 523.133247 368.375974 518.36953 C 370.349171 513.605813 371.364832 508.49974 371.364832 503.343529 -" clip-path="url(#p3dcb02ba35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p8353e7c1e6)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3221,7 +3221,7 @@ C 338.974947 555.696638 345.783044 554.342424 352.134667 551.711495 C 358.486291 549.080567 364.257917 545.22409 369.119238 540.362768 C 373.98056 535.501446 377.837037 529.72982 380.467966 523.378197 C 383.098894 517.026574 384.453109 510.218477 384.453109 503.343529 -" clip-path="url(#p3dcb02ba35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p8353e7c1e6)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3249,7 +3249,7 @@ C 340.693684 568.784916 349.203805 567.092147 357.143334 563.803487 C 365.082863 560.514826 372.297396 555.69423 378.374048 549.617577 C 384.4507 543.540925 389.271297 536.326393 392.559957 528.386864 C 395.848618 520.447335 397.541386 511.937214 397.541386 503.343529 -" clip-path="url(#p3dcb02ba35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p8353e7c1e6)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3290,7 +3290,7 @@ L 319.595804 492.078386 L 321.714601 497.343486 L 317.82558 498.700705 L 325.646103 502.66314 -" clip-path="url(#p3dcb02ba35)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8353e7c1e6)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> + - + - + - + - + - + - + - + - 2024-11-21T17:17:13.523203 + 2024-11-21T17:25:39.341677 image/svg+xml @@ -43,7 +43,7 @@ L 144.371629 144.845217 L 144.371629 60.48 L 106.353262 60.48 z -" clip-path="url(#p869c68c7ec)" style="fill: #ffcc00; opacity: 0.4; stroke: #ffcc00; stroke-linejoin: miter"/> +" clip-path="url(#pdc08b8ccdb)" style="fill: #ffcc00; opacity: 0.4; stroke: #ffcc00; stroke-linejoin: miter"/> +" clip-path="url(#pdc08b8ccdb)" style="fill: #ff8000; opacity: 0.4; stroke: #ff8000; stroke-linejoin: miter"/> +" clip-path="url(#pdc08b8ccdb)" style="fill: #ff3300; opacity: 0.4; stroke: #ff3300; stroke-linejoin: miter"/> - - + - + - + - + - + - + - + @@ -121,12 +121,12 @@ L 0 3.5 - - + @@ -162,7 +162,7 @@ z - + @@ -203,7 +203,7 @@ z - + @@ -2574,7 +2574,7 @@ L 347.135933 102.001083 L 347.247453 141.010435 L 435.845455 141.010435 L 435.845455 141.010435 -" clip-path="url(#p869c68c7ec)" style="fill: none; stroke: #808080; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdc08b8ccdb)" style="fill: none; stroke: #808080; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf3d39575ad)" style="fill: #ffcc00; opacity: 0.4; stroke: #ffcc00; stroke-linejoin: miter"/> +" clip-path="url(#pf3d39575ad)" style="fill: #ff8000; opacity: 0.4; stroke: #ff8000; stroke-linejoin: miter"/> +" clip-path="url(#pf3d39575ad)" style="fill: #ff3300; opacity: 0.4; stroke: #ff3300; stroke-linejoin: miter"/> - + @@ -2786,7 +2786,7 @@ z - + @@ -2801,7 +2801,7 @@ z - + @@ -2828,7 +2828,7 @@ z - + @@ -2843,7 +2843,7 @@ z - + @@ -2899,7 +2899,7 @@ z - + @@ -2914,7 +2914,7 @@ z - + @@ -3063,7 +3063,7 @@ z - + @@ -3076,7 +3076,7 @@ z - + @@ -3090,7 +3090,7 @@ z - + @@ -3130,7 +3130,7 @@ z - + @@ -3519,7 +3519,7 @@ L 347.994704 238.694945 L 348.919849 238.721029 L 435.845455 238.721067 L 435.845455 238.721067 -" clip-path="url(#pcc474ca166)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf3d39575ad)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf3d39575ad)" style="fill: none; stroke: #ff6347; stroke-width: 1.5; stroke-linecap: square"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4022,7 +4022,7 @@ z - + @@ -4076,7 +4076,7 @@ z - + @@ -4091,7 +4091,7 @@ z - + @@ -4106,7 +4106,7 @@ z - + @@ -4136,7 +4136,7 @@ z - + @@ -4160,7 +4160,7 @@ z - + @@ -4175,7 +4175,7 @@ z - + @@ -4190,7 +4190,7 @@ z - + @@ -4205,7 +4205,7 @@ z - + @@ -4243,7 +4243,7 @@ z +" clip-path="url(#pdca778fba3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> @@ -4389,7 +4389,7 @@ L 170.292366 294.44427 L 171.26745 304.047457 L 172.660428 317.946596 L 172.660428 317.946596 -" clip-path="url(#pcccbc1b167)" style="fill: none; stroke: #ff6347; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdca778fba3)" style="fill: none; stroke: #ff6347; stroke-width: 1.5; stroke-linecap: square"/> - + @@ -4440,7 +4440,7 @@ z - + @@ -4455,7 +4455,7 @@ z - + @@ -4485,7 +4485,7 @@ z - + @@ -4498,7 +4498,7 @@ z - + @@ -4511,7 +4511,7 @@ z - + @@ -4525,7 +4525,7 @@ z - + @@ -4539,7 +4539,7 @@ z - + @@ -4668,22 +4668,22 @@ L 289.65941 338.308585 L 291.644404 338.34365 L 310.519251 338.343907 L 310.519251 338.343907 -" clip-path="url(#p3d7d35ba68)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p04163e9e16)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> - - - - - - - - - - - - - + + + + + + + + + + + + + @@ -4776,7 +4776,7 @@ L 307.663647 332.826592 L 308.499434 333.906454 L 310.519251 336.643194 L 310.519251 336.643194 -" clip-path="url(#p3d7d35ba68)" style="fill: none; stroke: #ff6347; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p04163e9e16)" style="fill: none; stroke: #ff6347; stroke-width: 1.5; stroke-linecap: square"/> - + @@ -4827,7 +4827,7 @@ z - + @@ -4842,7 +4842,7 @@ z - + @@ -4872,7 +4872,7 @@ z - + @@ -4885,7 +4885,7 @@ z - + @@ -4899,7 +4899,7 @@ z - + @@ -4913,7 +4913,7 @@ z - + @@ -5099,38 +5099,38 @@ L 447.333342 334.796436 L 447.925357 337.225652 L 448.378075 338.40525 L 448.378075 338.40525 -" clip-path="url(#p5a0c7bb1f8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf509139387)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -5282,7 +5282,7 @@ L 446.323433 321.526368 L 448.02983 332.702555 L 448.378075 334.352229 L 448.378075 334.352229 -" clip-path="url(#p5a0c7bb1f8)" style="fill: none; stroke: #ff6347; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf509139387)" style="fill: none; stroke: #ff6347; stroke-width: 1.5; stroke-linecap: square"/> + - + - + - + - + diff --git a/docs/assets/thumbnails/tutorials/plot_02_head_direction.svg b/docs/assets/thumbnails/tutorials/plot_02_head_direction.svg index 7f217316..7287c79b 100644 --- a/docs/assets/thumbnails/tutorials/plot_02_head_direction.svg +++ b/docs/assets/thumbnails/tutorials/plot_02_head_direction.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:17:37.779160 + 2024-11-21T17:26:02.746370 image/svg+xml @@ -43,7 +43,7 @@ L 113.445378 87.755294 L 113.445378 69.12 L 90 69.12 z -" clip-path="url(#p12301efd11)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p9590a81315)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -128,12 +128,12 @@ L 111.570287 80.646993 L 111.840085 80.657057 L 112.109882 80.662992 L 112.379679 80.664939 -" clip-path="url(#p12301efd11)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9590a81315)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9590a81315)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -151,7 +151,7 @@ L 141.579832 87.755294 L 141.579832 69.12 L 118.134454 69.12 z -" clip-path="url(#pd3eb448ffb)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> +" clip-path="url(#ped2653a965)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> @@ -236,12 +236,12 @@ L 139.704741 80.675468 L 139.974538 80.669563 L 140.244336 80.666081 L 140.514133 80.664939 -" clip-path="url(#pd3eb448ffb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#ped2653a965)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#ped2653a965)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -259,7 +259,7 @@ L 169.714286 87.755294 L 169.714286 69.12 L 146.268908 69.12 z -" clip-path="url(#p8017432f3e)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> +" clip-path="url(#p21e72f14b9)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> @@ -344,12 +344,12 @@ L 167.839195 80.658153 L 168.108992 80.661958 L 168.378789 80.664202 L 168.648587 80.664939 -" clip-path="url(#p8017432f3e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p21e72f14b9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p21e72f14b9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -367,7 +367,7 @@ L 197.848739 87.755294 L 197.848739 69.12 L 174.403361 69.12 z -" clip-path="url(#p8abb1002f1)" style="fill: #ff7d7d; opacity: 0.5; stroke: #ff7d7d; stroke-linejoin: miter"/> +" clip-path="url(#pd888b325d1)" style="fill: #ff7d7d; opacity: 0.5; stroke: #ff7d7d; stroke-linejoin: miter"/> @@ -452,12 +452,12 @@ L 195.973649 80.651515 L 196.243446 80.659043 L 196.513243 80.663482 L 196.78304 80.664939 -" clip-path="url(#p8abb1002f1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd888b325d1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd888b325d1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -475,7 +475,7 @@ L 225.983193 87.755294 L 225.983193 69.12 L 202.537815 69.12 z -" clip-path="url(#p8a3b5353c9)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> +" clip-path="url(#p95efffb43f)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> @@ -560,12 +560,12 @@ L 224.108103 80.667353 L 224.3779 80.665999 L 224.647697 80.665201 L 224.917494 80.664939 -" clip-path="url(#p8a3b5353c9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p95efffb43f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p95efffb43f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -583,7 +583,7 @@ L 254.117647 87.755294 L 254.117647 69.12 L 230.672269 69.12 z -" clip-path="url(#p63156f34a4)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#p1ef9ae295b)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -668,12 +668,12 @@ L 252.242556 80.665808 L 252.512354 80.66532 L 252.782151 80.665033 L 253.051948 80.664939 -" clip-path="url(#p63156f34a4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1ef9ae295b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1ef9ae295b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -691,7 +691,7 @@ L 282.252101 87.755294 L 282.252101 69.12 L 258.806723 69.12 z -" clip-path="url(#pc5ffc28e1a)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> +" clip-path="url(#p5c85405ac8)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> @@ -776,12 +776,12 @@ L 280.37701 80.673901 L 280.646807 80.668875 L 280.916605 80.665911 L 281.186402 80.664939 -" clip-path="url(#pc5ffc28e1a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5c85405ac8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5c85405ac8)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -799,7 +799,7 @@ L 310.386555 87.755294 L 310.386555 69.12 L 286.941176 69.12 z -" clip-path="url(#p10ffe396ce)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> +" clip-path="url(#p95abf522b5)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> @@ -884,12 +884,12 @@ L 308.511464 80.678772 L 308.781261 80.671014 L 309.051058 80.666439 L 309.320856 80.664939 -" clip-path="url(#p10ffe396ce)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p95abf522b5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p95abf522b5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -907,7 +907,7 @@ L 338.521008 87.755294 L 338.521008 69.12 L 315.07563 69.12 z -" clip-path="url(#p6fc099c423)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> +" clip-path="url(#p3771ff3267)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> @@ -992,12 +992,12 @@ L 336.645918 80.677684 L 336.915715 80.670536 L 337.185512 80.666321 L 337.455309 80.664939 -" clip-path="url(#p6fc099c423)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3771ff3267)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3771ff3267)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1015,7 +1015,7 @@ L 366.655462 87.755294 L 366.655462 69.12 L 343.210084 69.12 z -" clip-path="url(#p8f67974980)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> +" clip-path="url(#pf7bf9e5299)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> @@ -1100,12 +1100,12 @@ L 364.780372 80.667048 L 365.050169 80.665865 L 365.319966 80.665167 L 365.589763 80.664939 -" clip-path="url(#p8f67974980)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf7bf9e5299)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf7bf9e5299)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1123,7 +1123,7 @@ L 394.789916 87.755294 L 394.789916 69.12 L 371.344538 69.12 z -" clip-path="url(#p3e50034b52)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> +" clip-path="url(#pf0a5849ca8)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> @@ -1208,12 +1208,12 @@ L 392.914825 80.672311 L 393.184623 80.668177 L 393.45442 80.665738 L 393.724217 80.664939 -" clip-path="url(#p3e50034b52)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf0a5849ca8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf0a5849ca8)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1231,7 +1231,7 @@ L 422.92437 87.755294 L 422.92437 69.12 L 399.478992 69.12 z -" clip-path="url(#p44573d5222)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> +" clip-path="url(#p200316afb5)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> @@ -1316,12 +1316,12 @@ L 421.049279 80.65606 L 421.319076 80.661039 L 421.588874 80.663975 L 421.858671 80.664939 -" clip-path="url(#p44573d5222)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p200316afb5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p200316afb5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1339,7 +1339,7 @@ L 451.058824 87.755294 L 451.058824 69.12 L 427.613445 69.12 z -" clip-path="url(#p8f0342cf01)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> +" clip-path="url(#pad92a48111)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> @@ -1424,12 +1424,12 @@ L 449.183733 80.676724 L 449.45353 80.670115 L 449.723327 80.666217 L 449.993125 80.664939 -" clip-path="url(#p8f0342cf01)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pad92a48111)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pad92a48111)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1447,7 +1447,7 @@ L 479.193277 87.755294 L 479.193277 69.12 L 455.747899 69.12 z -" clip-path="url(#pb74ec38913)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> +" clip-path="url(#p3421216d71)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> @@ -1532,12 +1532,12 @@ L 477.318187 80.667773 L 477.587984 80.666183 L 477.857781 80.665246 L 478.127578 80.664939 -" clip-path="url(#pb74ec38913)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3421216d71)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3421216d71)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1555,7 +1555,7 @@ L 507.327731 87.755294 L 507.327731 69.12 L 483.882353 69.12 z -" clip-path="url(#p8dbaace941)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> +" clip-path="url(#pc6344fed43)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> @@ -1640,12 +1640,12 @@ L 505.45264 80.664428 L 505.722438 80.664714 L 505.992235 80.664883 L 506.262032 80.664939 -" clip-path="url(#p8dbaace941)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc6344fed43)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc6344fed43)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1663,7 +1663,7 @@ L 535.462185 87.755294 L 535.462185 69.12 L 512.016807 69.12 z -" clip-path="url(#pa2682b703d)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> +" clip-path="url(#p9c3388eefb)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> @@ -1748,12 +1748,12 @@ L 533.587094 80.672024 L 533.856891 80.66805 L 534.126689 80.665707 L 534.396486 80.664939 -" clip-path="url(#pa2682b703d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9c3388eefb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9c3388eefb)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1771,7 +1771,7 @@ L 563.596639 87.755294 L 563.596639 69.12 L 540.151261 69.12 z -" clip-path="url(#pea9b6bf18c)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> +" clip-path="url(#p64e53a82c9)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> @@ -1856,12 +1856,12 @@ L 561.721548 80.665934 L 561.991345 80.665376 L 562.261142 80.665047 L 562.53094 80.664939 -" clip-path="url(#pea9b6bf18c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p64e53a82c9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p64e53a82c9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1879,7 +1879,7 @@ L 591.731092 87.755294 L 591.731092 69.12 L 568.285714 69.12 z -" clip-path="url(#pe822f11109)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> +" clip-path="url(#p650d99ddf4)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> @@ -1964,12 +1964,12 @@ L 589.856002 80.685519 L 590.125799 80.673978 L 590.395596 80.667171 L 590.665393 80.664939 -" clip-path="url(#pe822f11109)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p650d99ddf4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p650d99ddf4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1987,7 +1987,7 @@ L 619.865546 87.755294 L 619.865546 69.12 L 596.420168 69.12 z -" clip-path="url(#pff7d44b1d2)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#p7ab432cdc6)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -2072,12 +2072,12 @@ L 617.990456 80.670055 L 618.260253 80.667186 L 618.53005 80.665494 L 618.799847 80.664939 -" clip-path="url(#pff7d44b1d2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ab432cdc6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ab432cdc6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2095,7 +2095,7 @@ L 113.445378 110.117647 L 113.445378 91.482353 L 90 91.482353 z -" clip-path="url(#paa20ba2038)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> +" clip-path="url(#pa3f2babd0f)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> @@ -2180,12 +2180,12 @@ L 111.570287 102.767724 L 111.840085 102.769162 L 112.109882 102.77001 L 112.379679 102.770289 -" clip-path="url(#paa20ba2038)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa3f2babd0f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa3f2babd0f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2203,7 +2203,7 @@ L 141.579832 110.117647 L 141.579832 91.482353 L 118.134454 91.482353 z -" clip-path="url(#pcba12c8461)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p0a6ae21062)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -2288,12 +2288,12 @@ L 139.704741 102.758326 L 139.974538 102.765035 L 140.244336 102.768991 L 140.514133 102.770289 -" clip-path="url(#pcba12c8461)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0a6ae21062)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0a6ae21062)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2311,7 +2311,7 @@ L 169.714286 110.117647 L 169.714286 91.482353 L 146.268908 91.482353 z -" clip-path="url(#p0581f5f723)" style="fill: #ffbdbd; opacity: 0.5; stroke: #ffbdbd; stroke-linejoin: miter"/> +" clip-path="url(#p6499c9de80)" style="fill: #ffbdbd; opacity: 0.5; stroke: #ffbdbd; stroke-linejoin: miter"/> @@ -2396,12 +2396,12 @@ L 167.839195 102.771472 L 168.108992 102.770809 L 168.378789 102.770417 L 168.648587 102.770289 -" clip-path="url(#p0581f5f723)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6499c9de80)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6499c9de80)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2419,7 +2419,7 @@ L 197.848739 110.117647 L 197.848739 91.482353 L 174.403361 91.482353 z -" clip-path="url(#p4f967e9e71)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> +" clip-path="url(#p60047dcf36)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> @@ -2504,12 +2504,12 @@ L 195.973649 102.765973 L 196.243446 102.768393 L 196.513243 102.769821 L 196.78304 102.770289 -" clip-path="url(#p4f967e9e71)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p60047dcf36)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p60047dcf36)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2527,7 +2527,7 @@ L 225.983193 110.117647 L 225.983193 91.482353 L 202.537815 91.482353 z -" clip-path="url(#p47a659cec8)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> +" clip-path="url(#pc379ed8b79)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> @@ -2612,12 +2612,12 @@ L 224.108103 102.773462 L 224.3779 102.771683 L 224.647697 102.770633 L 224.917494 102.770289 -" clip-path="url(#p47a659cec8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc379ed8b79)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc379ed8b79)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2635,7 +2635,7 @@ L 254.117647 110.117647 L 254.117647 91.482353 L 230.672269 91.482353 z -" clip-path="url(#p155df5e32e)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> +" clip-path="url(#pf03389d2f9)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> @@ -2720,12 +2720,12 @@ L 252.242556 102.778909 L 252.512354 102.774075 L 252.782151 102.771224 L 253.051948 102.770289 -" clip-path="url(#p155df5e32e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf03389d2f9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf03389d2f9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2743,7 +2743,7 @@ L 282.252101 110.117647 L 282.252101 91.482353 L 258.806723 91.482353 z -" clip-path="url(#pa12c83360d)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#p3eae332b79)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -2828,12 +2828,12 @@ L 280.37701 102.770016 L 280.646807 102.770169 L 280.916605 102.770259 L 281.186402 102.770289 -" clip-path="url(#pa12c83360d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3eae332b79)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3eae332b79)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2851,7 +2851,7 @@ L 310.386555 110.117647 L 310.386555 91.482353 L 286.941176 91.482353 z -" clip-path="url(#pc6ae6bab4b)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#p20af343335)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -2936,12 +2936,12 @@ L 308.511464 102.773679 L 308.781261 102.771778 L 309.051058 102.770657 L 309.320856 102.770289 -" clip-path="url(#pc6ae6bab4b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p20af343335)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p20af343335)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2959,7 +2959,7 @@ L 338.521008 110.117647 L 338.521008 91.482353 L 315.07563 91.482353 z -" clip-path="url(#p9ee13aa270)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> +" clip-path="url(#p382751b9e5)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> @@ -3044,12 +3044,12 @@ L 336.645918 102.768967 L 336.915715 102.769708 L 337.185512 102.770145 L 337.455309 102.770289 -" clip-path="url(#p9ee13aa270)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p382751b9e5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p382751b9e5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3067,7 +3067,7 @@ L 366.655462 110.117647 L 366.655462 91.482353 L 343.210084 91.482353 z -" clip-path="url(#p0b4afa0955)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#pb7e90b8788)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -3152,12 +3152,12 @@ L 364.780372 102.764435 L 365.050169 102.767718 L 365.319966 102.769654 L 365.589763 102.770289 -" clip-path="url(#p0b4afa0955)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb7e90b8788)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb7e90b8788)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3175,7 +3175,7 @@ L 394.789916 110.117647 L 394.789916 91.482353 L 371.344538 91.482353 z -" clip-path="url(#pa5f043a5e6)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#pb93a46db6b)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -3260,12 +3260,12 @@ L 392.914825 102.766145 L 393.184623 102.768469 L 393.45442 102.769839 L 393.724217 102.770289 -" clip-path="url(#pa5f043a5e6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb93a46db6b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb93a46db6b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3283,7 +3283,7 @@ L 422.92437 110.117647 L 422.92437 91.482353 L 399.478992 91.482353 z -" clip-path="url(#p6e8d73e255)" style="fill: #ffb1b1; opacity: 0.5; stroke: #ffb1b1; stroke-linejoin: miter"/> +" clip-path="url(#pcc56fa2cda)" style="fill: #ffb1b1; opacity: 0.5; stroke: #ffb1b1; stroke-linejoin: miter"/> @@ -3368,12 +3368,12 @@ L 421.049279 102.771276 L 421.319076 102.770722 L 421.588874 102.770396 L 421.858671 102.770289 -" clip-path="url(#p6e8d73e255)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcc56fa2cda)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcc56fa2cda)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3391,7 +3391,7 @@ L 451.058824 110.117647 L 451.058824 91.482353 L 427.613445 91.482353 z -" clip-path="url(#pe534c56b31)" style="fill: #8585ff; opacity: 0.5; stroke: #8585ff; stroke-linejoin: miter"/> +" clip-path="url(#p7bfee2d109)" style="fill: #8585ff; opacity: 0.5; stroke: #8585ff; stroke-linejoin: miter"/> @@ -3476,12 +3476,12 @@ L 449.183733 102.785121 L 449.45353 102.776803 L 449.723327 102.771898 L 449.993125 102.770289 -" clip-path="url(#pe534c56b31)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7bfee2d109)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7bfee2d109)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3499,7 +3499,7 @@ L 479.193277 110.117647 L 479.193277 91.482353 L 455.747899 91.482353 z -" clip-path="url(#p79f1ffd4a1)" style="fill: #ffbdbd; opacity: 0.5; stroke: #ffbdbd; stroke-linejoin: miter"/> +" clip-path="url(#p4ad6db2323)" style="fill: #ffbdbd; opacity: 0.5; stroke: #ffbdbd; stroke-linejoin: miter"/> @@ -3584,12 +3584,12 @@ L 477.318187 102.761584 L 477.587984 102.766466 L 477.857781 102.769344 L 478.127578 102.770289 -" clip-path="url(#p79f1ffd4a1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4ad6db2323)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4ad6db2323)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3607,7 +3607,7 @@ L 507.327731 110.117647 L 507.327731 91.482353 L 483.882353 91.482353 z -" clip-path="url(#p749537adc3)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#p12a77b8c26)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -3692,12 +3692,12 @@ L 505.45264 102.779033 L 505.722438 102.774129 L 505.992235 102.771237 L 506.262032 102.770289 -" clip-path="url(#p749537adc3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p12a77b8c26)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p12a77b8c26)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3715,7 +3715,7 @@ L 535.462185 110.117647 L 535.462185 91.482353 L 512.016807 91.482353 z -" clip-path="url(#p971e814e84)" style="fill: #ffc5c5; opacity: 0.5; stroke: #ffc5c5; stroke-linejoin: miter"/> +" clip-path="url(#p73580380b9)" style="fill: #ffc5c5; opacity: 0.5; stroke: #ffc5c5; stroke-linejoin: miter"/> @@ -3800,12 +3800,12 @@ L 533.587094 102.762505 L 533.856891 102.76687 L 534.126689 102.769444 L 534.396486 102.770289 -" clip-path="url(#p971e814e84)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p73580380b9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p73580380b9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3823,7 +3823,7 @@ L 563.596639 110.117647 L 563.596639 91.482353 L 540.151261 91.482353 z -" clip-path="url(#p6b5c54924d)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> +" clip-path="url(#p425002ee93)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> @@ -3908,12 +3908,12 @@ L 561.721548 102.773989 L 561.991345 102.771914 L 562.261142 102.77069 L 562.53094 102.770289 -" clip-path="url(#p6b5c54924d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p425002ee93)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p425002ee93)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3931,7 +3931,7 @@ L 591.731092 110.117647 L 591.731092 91.482353 L 568.285714 91.482353 z -" clip-path="url(#p443daa1a85)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> +" clip-path="url(#p5e78a0206a)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> @@ -4016,12 +4016,12 @@ L 589.856002 102.786793 L 590.125799 102.777538 L 590.395596 102.772079 L 590.665393 102.770289 -" clip-path="url(#p443daa1a85)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5e78a0206a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5e78a0206a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4039,7 +4039,7 @@ L 619.865546 110.117647 L 619.865546 91.482353 L 596.420168 91.482353 z -" clip-path="url(#p71fdfe8818)" style="fill: #adadff; opacity: 0.5; stroke: #adadff; stroke-linejoin: miter"/> +" clip-path="url(#pc6037ca084)" style="fill: #adadff; opacity: 0.5; stroke: #adadff; stroke-linejoin: miter"/> @@ -4124,12 +4124,12 @@ L 617.990456 102.780009 L 618.260253 102.774558 L 618.53005 102.771343 L 618.799847 102.770289 -" clip-path="url(#p71fdfe8818)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc6037ca084)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc6037ca084)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4147,7 +4147,7 @@ L 113.445378 132.48 L 113.445378 113.844706 L 90 113.844706 z -" clip-path="url(#p9f66a72a57)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> +" clip-path="url(#pce7f51428d)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> @@ -4232,12 +4232,12 @@ L 111.570287 125.513942 L 111.840085 125.514648 L 112.109882 125.515065 L 112.379679 125.515202 -" clip-path="url(#p9f66a72a57)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pce7f51428d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pce7f51428d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4255,7 +4255,7 @@ L 141.579832 132.48 L 141.579832 113.844706 L 118.134454 113.844706 z -" clip-path="url(#p1fc8352651)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> +" clip-path="url(#p919d840972)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> @@ -4340,12 +4340,12 @@ L 139.704741 125.520056 L 139.974538 125.517334 L 140.244336 125.515728 L 140.514133 125.515202 -" clip-path="url(#p1fc8352651)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p919d840972)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p919d840972)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4363,7 +4363,7 @@ L 169.714286 132.48 L 169.714286 113.844706 L 146.268908 113.844706 z -" clip-path="url(#p1ef4124dce)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#pb15abc7d5c)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -4448,12 +4448,12 @@ L 167.839195 125.514499 L 168.108992 125.514893 L 168.378789 125.515125 L 168.648587 125.515202 -" clip-path="url(#p1ef4124dce)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb15abc7d5c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb15abc7d5c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4471,7 +4471,7 @@ L 197.848739 132.48 L 197.848739 113.844706 L 174.403361 113.844706 z -" clip-path="url(#pc3d2c2d86d)" style="fill: #fffdfd; opacity: 0.5; stroke: #fffdfd; stroke-linejoin: miter"/> +" clip-path="url(#pbd9f680977)" style="fill: #fffdfd; opacity: 0.5; stroke: #fffdfd; stroke-linejoin: miter"/> @@ -4556,12 +4556,12 @@ L 195.973649 125.522113 L 196.243446 125.518237 L 196.513243 125.515951 L 196.78304 125.515202 -" clip-path="url(#pc3d2c2d86d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbd9f680977)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbd9f680977)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4579,7 +4579,7 @@ L 225.983193 132.48 L 225.983193 113.844706 L 202.537815 113.844706 z -" clip-path="url(#pbbc43a80cc)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> +" clip-path="url(#p1643e33e10)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> @@ -4664,12 +4664,12 @@ L 224.108103 125.512703 L 224.3779 125.514104 L 224.647697 125.514931 L 224.917494 125.515202 -" clip-path="url(#pbbc43a80cc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1643e33e10)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1643e33e10)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4687,7 +4687,7 @@ L 254.117647 132.48 L 254.117647 113.844706 L 230.672269 113.844706 z -" clip-path="url(#peb7f1b6323)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> +" clip-path="url(#pf40ff6d0e7)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> @@ -4772,12 +4772,12 @@ L 252.242556 125.524869 L 252.512354 125.519447 L 252.782151 125.51625 L 253.051948 125.515202 -" clip-path="url(#peb7f1b6323)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf40ff6d0e7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf40ff6d0e7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4795,7 +4795,7 @@ L 282.252101 132.48 L 282.252101 113.844706 L 258.806723 113.844706 z -" clip-path="url(#p7767b7b15c)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> +" clip-path="url(#pc49e2dd58b)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> @@ -4880,12 +4880,12 @@ L 280.37701 125.520904 L 280.646807 125.517706 L 280.916605 125.51582 L 281.186402 125.515202 -" clip-path="url(#p7767b7b15c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc49e2dd58b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc49e2dd58b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4903,7 +4903,7 @@ L 310.386555 132.48 L 310.386555 113.844706 L 286.941176 113.844706 z -" clip-path="url(#pcec7450c06)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> +" clip-path="url(#pe9ba0adafe)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> @@ -4988,12 +4988,12 @@ L 308.511464 125.516419 L 308.781261 125.515736 L 309.051058 125.515334 L 309.320856 125.515202 -" clip-path="url(#pcec7450c06)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe9ba0adafe)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe9ba0adafe)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5011,7 +5011,7 @@ L 338.521008 132.48 L 338.521008 113.844706 L 315.07563 113.844706 z -" clip-path="url(#pd128c0de9b)" style="fill: #9595ff; opacity: 0.5; stroke: #9595ff; stroke-linejoin: miter"/> +" clip-path="url(#pfdcc28bb2a)" style="fill: #9595ff; opacity: 0.5; stroke: #9595ff; stroke-linejoin: miter"/> @@ -5096,12 +5096,12 @@ L 336.645918 125.518916 L 336.915715 125.516833 L 337.185512 125.515604 L 337.455309 125.515202 -" clip-path="url(#pd128c0de9b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfdcc28bb2a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfdcc28bb2a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5119,7 +5119,7 @@ L 366.655462 132.48 L 366.655462 113.844706 L 343.210084 113.844706 z -" clip-path="url(#p025b0c80e1)" style="fill: #5959ff; opacity: 0.5; stroke: #5959ff; stroke-linejoin: miter"/> +" clip-path="url(#pd552e9b60a)" style="fill: #5959ff; opacity: 0.5; stroke: #5959ff; stroke-linejoin: miter"/> @@ -5204,12 +5204,12 @@ L 364.780372 125.522911 L 365.050169 125.518588 L 365.319966 125.516038 L 365.589763 125.515202 -" clip-path="url(#p025b0c80e1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd552e9b60a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd552e9b60a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5227,7 +5227,7 @@ L 394.789916 132.48 L 394.789916 113.844706 L 371.344538 113.844706 z -" clip-path="url(#p483f0e33b9)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> +" clip-path="url(#p00eb151a02)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> @@ -5312,12 +5312,12 @@ L 392.914825 125.515675 L 393.184623 125.515409 L 393.45442 125.515253 L 393.724217 125.515202 -" clip-path="url(#p483f0e33b9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p00eb151a02)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p00eb151a02)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5335,7 +5335,7 @@ L 422.92437 132.48 L 422.92437 113.844706 L 399.478992 113.844706 z -" clip-path="url(#pdc246cce6d)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> +" clip-path="url(#pbd79e5699e)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> @@ -5420,12 +5420,12 @@ L 421.049279 125.509866 L 421.319076 125.512858 L 421.588874 125.514623 L 421.858671 125.515202 -" clip-path="url(#pdc246cce6d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbd79e5699e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbd79e5699e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5443,7 +5443,7 @@ L 451.058824 132.48 L 451.058824 113.844706 L 427.613445 113.844706 z -" clip-path="url(#p8ab5748e59)" style="fill: #3535ff; opacity: 0.5; stroke: #3535ff; stroke-linejoin: miter"/> +" clip-path="url(#p2f5bc6f690)" style="fill: #3535ff; opacity: 0.5; stroke: #3535ff; stroke-linejoin: miter"/> @@ -5528,12 +5528,12 @@ L 449.183733 125.529886 L 449.45353 125.521651 L 449.723327 125.516795 L 449.993125 125.515202 -" clip-path="url(#p8ab5748e59)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2f5bc6f690)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2f5bc6f690)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5551,7 +5551,7 @@ L 479.193277 132.48 L 479.193277 113.844706 L 455.747899 113.844706 z -" clip-path="url(#peca0aff093)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> +" clip-path="url(#pf9452764f3)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> @@ -5636,12 +5636,12 @@ L 477.318187 125.518861 L 477.587984 125.516809 L 477.857781 125.515598 L 478.127578 125.515202 -" clip-path="url(#peca0aff093)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf9452764f3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf9452764f3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5659,7 +5659,7 @@ L 507.327731 132.48 L 507.327731 113.844706 L 483.882353 113.844706 z -" clip-path="url(#p95f2cc2d69)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> +" clip-path="url(#p6fe904d702)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> @@ -5744,12 +5744,12 @@ L 505.45264 125.51748 L 505.722438 125.516202 L 505.992235 125.515449 L 506.262032 125.515202 -" clip-path="url(#p95f2cc2d69)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6fe904d702)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6fe904d702)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5767,7 +5767,7 @@ L 535.462185 132.48 L 535.462185 113.844706 L 512.016807 113.844706 z -" clip-path="url(#pe68e197ce6)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> +" clip-path="url(#p72501c00b0)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> @@ -5852,12 +5852,12 @@ L 533.587094 125.511616 L 533.856891 125.513627 L 534.126689 125.514813 L 534.396486 125.515202 -" clip-path="url(#pe68e197ce6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p72501c00b0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p72501c00b0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5875,7 +5875,7 @@ L 563.596639 132.48 L 563.596639 113.844706 L 540.151261 113.844706 z -" clip-path="url(#pda78186180)" style="fill: #ddddff; opacity: 0.5; stroke: #ddddff; stroke-linejoin: miter"/> +" clip-path="url(#pa9869eebb9)" style="fill: #ddddff; opacity: 0.5; stroke: #ddddff; stroke-linejoin: miter"/> @@ -5960,12 +5960,12 @@ L 561.721548 125.511292 L 561.991345 125.513484 L 562.261142 125.514777 L 562.53094 125.515202 -" clip-path="url(#pda78186180)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa9869eebb9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa9869eebb9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5983,7 +5983,7 @@ L 591.731092 132.48 L 591.731092 113.844706 L 568.285714 113.844706 z -" clip-path="url(#peb5f14db36)" style="fill: #3939ff; opacity: 0.5; stroke: #3939ff; stroke-linejoin: miter"/> +" clip-path="url(#p854651f5fe)" style="fill: #3939ff; opacity: 0.5; stroke: #3939ff; stroke-linejoin: miter"/> @@ -6068,12 +6068,12 @@ L 589.856002 125.532233 L 590.125799 125.522682 L 590.395596 125.517049 L 590.665393 125.515202 -" clip-path="url(#peb5f14db36)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p854651f5fe)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p854651f5fe)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6091,7 +6091,7 @@ L 619.865546 132.48 L 619.865546 113.844706 L 596.420168 113.844706 z -" clip-path="url(#p671291ff40)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> +" clip-path="url(#p40be0f2b81)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> @@ -6176,12 +6176,12 @@ L 617.990456 125.521835 L 618.260253 125.518115 L 618.53005 125.515921 L 618.799847 125.515202 -" clip-path="url(#p671291ff40)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p40be0f2b81)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p40be0f2b81)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6199,7 +6199,7 @@ L 113.445378 154.842353 L 113.445378 136.207059 L 90 136.207059 z -" clip-path="url(#p868db90bdc)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> +" clip-path="url(#p76dc0f3bd0)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> @@ -6284,12 +6284,12 @@ L 111.570287 145.333485 L 111.840085 145.339008 L 112.109882 145.342264 L 112.379679 145.343333 -" clip-path="url(#p868db90bdc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p76dc0f3bd0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p76dc0f3bd0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6307,7 +6307,7 @@ L 141.579832 154.842353 L 141.579832 136.207059 L 118.134454 136.207059 z -" clip-path="url(#pf3897ab9ac)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> +" clip-path="url(#pa2b0401fba)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> @@ -6392,12 +6392,12 @@ L 139.704741 145.330453 L 139.974538 145.337676 L 140.244336 145.341935 L 140.514133 145.343333 -" clip-path="url(#pf3897ab9ac)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa2b0401fba)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa2b0401fba)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6415,7 +6415,7 @@ L 169.714286 154.842353 L 169.714286 136.207059 L 146.268908 136.207059 z -" clip-path="url(#p2727725f25)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> +" clip-path="url(#pee2fc5deb4)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> @@ -6500,12 +6500,12 @@ L 167.839195 145.346775 L 168.108992 145.344845 L 168.378789 145.343706 L 168.648587 145.343333 -" clip-path="url(#p2727725f25)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pee2fc5deb4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pee2fc5deb4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6523,7 +6523,7 @@ L 197.848739 154.842353 L 197.848739 136.207059 L 174.403361 136.207059 z -" clip-path="url(#pa995662f1c)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#pc847b639a1)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -6608,12 +6608,12 @@ L 195.973649 145.325163 L 196.243446 145.335353 L 196.513243 145.341362 L 196.78304 145.343333 -" clip-path="url(#pa995662f1c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc847b639a1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc847b639a1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6631,7 +6631,7 @@ L 225.983193 154.842353 L 225.983193 136.207059 L 202.537815 136.207059 z -" clip-path="url(#p5ef8c39a61)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> +" clip-path="url(#pa5c6c4376c)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> @@ -6716,12 +6716,12 @@ L 224.108103 145.336531 L 224.3779 145.340345 L 224.647697 145.342595 L 224.917494 145.343333 -" clip-path="url(#p5ef8c39a61)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa5c6c4376c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa5c6c4376c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6739,7 +6739,7 @@ L 254.117647 154.842353 L 254.117647 136.207059 L 230.672269 136.207059 z -" clip-path="url(#pf234922f7e)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> +" clip-path="url(#pf042cc27ef)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> @@ -6824,12 +6824,12 @@ L 252.242556 145.354306 L 252.512354 145.348152 L 252.782151 145.344523 L 253.051948 145.343333 -" clip-path="url(#pf234922f7e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf042cc27ef)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf042cc27ef)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6847,7 +6847,7 @@ L 282.252101 154.842353 L 282.252101 136.207059 L 258.806723 136.207059 z -" clip-path="url(#p9c402b563d)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> +" clip-path="url(#pea10ea2257)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> @@ -6932,12 +6932,12 @@ L 280.37701 145.360615 L 280.646807 145.350923 L 280.916605 145.345207 L 281.186402 145.343333 -" clip-path="url(#p9c402b563d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pea10ea2257)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pea10ea2257)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6955,7 +6955,7 @@ L 310.386555 154.842353 L 310.386555 136.207059 L 286.941176 136.207059 z -" clip-path="url(#p10d7fd63f4)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> +" clip-path="url(#p1faeb4759d)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> @@ -7040,12 +7040,12 @@ L 308.511464 145.358301 L 308.781261 145.349907 L 309.051058 145.344956 L 309.320856 145.343333 -" clip-path="url(#p10d7fd63f4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1faeb4759d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1faeb4759d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7063,7 +7063,7 @@ L 338.521008 154.842353 L 338.521008 136.207059 L 315.07563 136.207059 z -" clip-path="url(#pe14aaf34f5)" style="fill: #5555ff; opacity: 0.5; stroke: #5555ff; stroke-linejoin: miter"/> +" clip-path="url(#p8f6a2c0a97)" style="fill: #5555ff; opacity: 0.5; stroke: #5555ff; stroke-linejoin: miter"/> @@ -7148,12 +7148,12 @@ L 336.645918 145.368196 L 336.915715 145.354253 L 337.185512 145.34603 L 337.455309 145.343333 -" clip-path="url(#pe14aaf34f5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8f6a2c0a97)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8f6a2c0a97)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7171,7 +7171,7 @@ L 366.655462 154.842353 L 366.655462 136.207059 L 343.210084 136.207059 z -" clip-path="url(#p7283f5ac9a)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> +" clip-path="url(#pdf16cac5ae)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> @@ -7256,12 +7256,12 @@ L 364.780372 145.3529 L 365.050169 145.347535 L 365.319966 145.34437 L 365.589763 145.343333 -" clip-path="url(#p7283f5ac9a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdf16cac5ae)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdf16cac5ae)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7279,7 +7279,7 @@ L 394.789916 154.842353 L 394.789916 136.207059 L 371.344538 136.207059 z -" clip-path="url(#p6957460ff0)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#pd800546816)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -7364,12 +7364,12 @@ L 392.914825 145.348299 L 393.184623 145.345514 L 393.45442 145.343871 L 393.724217 145.343333 -" clip-path="url(#p6957460ff0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd800546816)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd800546816)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7387,7 +7387,7 @@ L 422.92437 154.842353 L 422.92437 136.207059 L 399.478992 136.207059 z -" clip-path="url(#p52fedb8d00)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> +" clip-path="url(#p677fe0f90b)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> @@ -7472,12 +7472,12 @@ L 421.049279 145.344643 L 421.319076 145.343908 L 421.588874 145.343475 L 421.858671 145.343333 -" clip-path="url(#p52fedb8d00)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p677fe0f90b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p677fe0f90b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7495,7 +7495,7 @@ L 451.058824 154.842353 L 451.058824 136.207059 L 427.613445 136.207059 z -" clip-path="url(#p32d623d05c)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> +" clip-path="url(#p28e2c629f7)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> @@ -7580,12 +7580,12 @@ L 449.183733 145.348759 L 449.45353 145.345716 L 449.723327 145.343921 L 449.993125 145.343333 -" clip-path="url(#p32d623d05c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p28e2c629f7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p28e2c629f7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7603,7 +7603,7 @@ L 479.193277 154.842353 L 479.193277 136.207059 L 455.747899 136.207059 z -" clip-path="url(#p1d03ff7a72)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> +" clip-path="url(#p2d28fb7b9b)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> @@ -7688,12 +7688,12 @@ L 477.318187 145.332951 L 477.587984 145.338773 L 477.857781 145.342206 L 478.127578 145.343333 -" clip-path="url(#p1d03ff7a72)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d28fb7b9b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d28fb7b9b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7711,7 +7711,7 @@ L 507.327731 154.842353 L 507.327731 136.207059 L 483.882353 136.207059 z -" clip-path="url(#p65704286df)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#pc3e7479958)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -7796,12 +7796,12 @@ L 505.45264 145.344208 L 505.722438 145.343717 L 505.992235 145.343428 L 506.262032 145.343333 -" clip-path="url(#p65704286df)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc3e7479958)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc3e7479958)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7819,7 +7819,7 @@ L 535.462185 154.842353 L 535.462185 136.207059 L 512.016807 136.207059 z -" clip-path="url(#pda4a128a94)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#pbe3033c7de)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -7904,12 +7904,12 @@ L 533.587094 145.342733 L 533.856891 145.343069 L 534.126689 145.343268 L 534.396486 145.343333 -" clip-path="url(#pda4a128a94)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbe3033c7de)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbe3033c7de)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7927,7 +7927,7 @@ L 563.596639 154.842353 L 563.596639 136.207059 L 540.151261 136.207059 z -" clip-path="url(#pba6fd0a718)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> +" clip-path="url(#pe7f1885902)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> @@ -8012,12 +8012,12 @@ L 561.721548 145.353708 L 561.991345 145.347889 L 562.261142 145.344458 L 562.53094 145.343333 -" clip-path="url(#pba6fd0a718)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe7f1885902)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe7f1885902)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8035,7 +8035,7 @@ L 591.731092 154.842353 L 591.731092 136.207059 L 568.285714 136.207059 z -" clip-path="url(#pf8c5535480)" style="fill: #4141ff; opacity: 0.5; stroke: #4141ff; stroke-linejoin: miter"/> +" clip-path="url(#pdf5344ba22)" style="fill: #4141ff; opacity: 0.5; stroke: #4141ff; stroke-linejoin: miter"/> @@ -8120,12 +8120,12 @@ L 589.856002 145.365246 L 590.125799 145.352957 L 590.395596 145.34571 L 590.665393 145.343333 -" clip-path="url(#pf8c5535480)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdf5344ba22)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdf5344ba22)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8143,7 +8143,7 @@ L 619.865546 154.842353 L 619.865546 136.207059 L 596.420168 136.207059 z -" clip-path="url(#p52e7370a09)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> +" clip-path="url(#pedd277f254)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> @@ -8228,12 +8228,12 @@ L 617.990456 145.350949 L 618.260253 145.346678 L 618.53005 145.344159 L 618.799847 145.343333 -" clip-path="url(#p52e7370a09)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pedd277f254)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pedd277f254)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8251,7 +8251,7 @@ L 113.445378 177.204706 L 113.445378 158.569412 L 90 158.569412 z -" clip-path="url(#p7b7d9c8861)" style="fill: #ffd1d1; opacity: 0.5; stroke: #ffd1d1; stroke-linejoin: miter"/> +" clip-path="url(#p3006782477)" style="fill: #ffd1d1; opacity: 0.5; stroke: #ffd1d1; stroke-linejoin: miter"/> @@ -8336,12 +8336,12 @@ L 111.570287 167.339939 L 111.840085 167.339927 L 112.109882 167.33992 L 112.379679 167.339918 -" clip-path="url(#p7b7d9c8861)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3006782477)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3006782477)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8359,7 +8359,7 @@ L 141.579832 177.204706 L 141.579832 158.569412 L 118.134454 158.569412 z -" clip-path="url(#pa869698614)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> +" clip-path="url(#p33f9acf7ff)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> @@ -8444,12 +8444,12 @@ L 139.704741 167.340277 L 139.974538 167.340076 L 140.244336 167.339957 L 140.514133 167.339918 -" clip-path="url(#pa869698614)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p33f9acf7ff)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p33f9acf7ff)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8467,7 +8467,7 @@ L 169.714286 177.204706 L 169.714286 158.569412 L 146.268908 158.569412 z -" clip-path="url(#p0056026b13)" style="fill: #ffb1b1; opacity: 0.5; stroke: #ffb1b1; stroke-linejoin: miter"/> +" clip-path="url(#p064a14cc9f)" style="fill: #ffb1b1; opacity: 0.5; stroke: #ffb1b1; stroke-linejoin: miter"/> @@ -8552,12 +8552,12 @@ L 167.839195 167.34262 L 168.108992 167.341105 L 168.378789 167.340211 L 168.648587 167.339918 -" clip-path="url(#p0056026b13)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p064a14cc9f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p064a14cc9f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8575,7 +8575,7 @@ L 197.848739 177.204706 L 197.848739 158.569412 L 174.403361 158.569412 z -" clip-path="url(#p6779ca5cc4)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> +" clip-path="url(#p788155f36e)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> @@ -8660,12 +8660,12 @@ L 195.973649 167.332598 L 196.243446 167.336703 L 196.513243 167.339124 L 196.78304 167.339918 -" clip-path="url(#p6779ca5cc4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p788155f36e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p788155f36e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8683,7 +8683,7 @@ L 225.983193 177.204706 L 225.983193 158.569412 L 202.537815 158.569412 z -" clip-path="url(#p6256e9eb02)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#pfeef4429b9)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -8768,12 +8768,12 @@ L 224.108103 167.332915 L 224.3779 167.336842 L 224.647697 167.339158 L 224.917494 167.339918 -" clip-path="url(#p6256e9eb02)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfeef4429b9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfeef4429b9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8791,7 +8791,7 @@ L 254.117647 177.204706 L 254.117647 158.569412 L 230.672269 158.569412 z -" clip-path="url(#p63e0742f41)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> +" clip-path="url(#p1a2dbf897e)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> @@ -8876,12 +8876,12 @@ L 252.242556 167.340242 L 252.512354 167.34006 L 252.782151 167.339953 L 253.051948 167.339918 -" clip-path="url(#p63e0742f41)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1a2dbf897e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1a2dbf897e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8899,7 +8899,7 @@ L 282.252101 177.204706 L 282.252101 158.569412 L 258.806723 158.569412 z -" clip-path="url(#p810e2e80b0)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> +" clip-path="url(#pc2db60778b)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> @@ -8984,12 +8984,12 @@ L 280.37701 167.338628 L 280.646807 167.339351 L 280.916605 167.339778 L 281.186402 167.339918 -" clip-path="url(#p810e2e80b0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc2db60778b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc2db60778b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9007,7 +9007,7 @@ L 310.386555 177.204706 L 310.386555 158.569412 L 286.941176 158.569412 z -" clip-path="url(#p21a2fa0dc5)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> +" clip-path="url(#p7913d3c78a)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> @@ -9092,12 +9092,12 @@ L 308.511464 167.335093 L 308.781261 167.337799 L 309.051058 167.339395 L 309.320856 167.339918 -" clip-path="url(#p21a2fa0dc5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7913d3c78a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7913d3c78a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9115,7 +9115,7 @@ L 338.521008 177.204706 L 338.521008 158.569412 L 315.07563 158.569412 z -" clip-path="url(#p38a94023d5)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> +" clip-path="url(#p904c3a0284)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> @@ -9200,12 +9200,12 @@ L 336.645918 167.343142 L 336.915715 167.341334 L 337.185512 167.340268 L 337.455309 167.339918 -" clip-path="url(#p38a94023d5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p904c3a0284)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p904c3a0284)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9223,7 +9223,7 @@ L 366.655462 177.204706 L 366.655462 158.569412 L 343.210084 158.569412 z -" clip-path="url(#p71f37b03da)" style="fill: #6565ff; opacity: 0.5; stroke: #6565ff; stroke-linejoin: miter"/> +" clip-path="url(#p178b8b3166)" style="fill: #6565ff; opacity: 0.5; stroke: #6565ff; stroke-linejoin: miter"/> @@ -9308,12 +9308,12 @@ L 364.780372 167.349718 L 365.050169 167.344222 L 365.319966 167.340981 L 365.589763 167.339918 -" clip-path="url(#p71f37b03da)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p178b8b3166)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p178b8b3166)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9331,7 +9331,7 @@ L 394.789916 177.204706 L 394.789916 158.569412 L 371.344538 158.569412 z -" clip-path="url(#pd050fccd69)" style="fill: #a9a9ff; opacity: 0.5; stroke: #a9a9ff; stroke-linejoin: miter"/> +" clip-path="url(#pfdcd416727)" style="fill: #a9a9ff; opacity: 0.5; stroke: #a9a9ff; stroke-linejoin: miter"/> @@ -9416,12 +9416,12 @@ L 392.914825 167.341655 L 393.184623 167.340681 L 393.45442 167.340106 L 393.724217 167.339918 -" clip-path="url(#pd050fccd69)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfdcd416727)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfdcd416727)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9439,7 +9439,7 @@ L 422.92437 177.204706 L 422.92437 158.569412 L 399.478992 158.569412 z -" clip-path="url(#pef4b787fce)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> +" clip-path="url(#p42a85e3edd)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> @@ -9524,12 +9524,12 @@ L 421.049279 167.354294 L 421.319076 167.346232 L 421.588874 167.341478 L 421.858671 167.339918 -" clip-path="url(#pef4b787fce)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p42a85e3edd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p42a85e3edd)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9547,7 +9547,7 @@ L 451.058824 177.204706 L 451.058824 158.569412 L 427.613445 158.569412 z -" clip-path="url(#pcfe518e987)" style="fill: #0000f7; opacity: 0.5; stroke: #0000f7; stroke-linejoin: miter"/> +" clip-path="url(#p01b40a8f61)" style="fill: #0000f7; opacity: 0.5; stroke: #0000f7; stroke-linejoin: miter"/> @@ -9632,12 +9632,12 @@ L 449.183733 167.3586 L 449.45353 167.348123 L 449.723327 167.341945 L 449.993125 167.339918 -" clip-path="url(#pcfe518e987)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p01b40a8f61)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p01b40a8f61)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9655,7 +9655,7 @@ L 479.193277 177.204706 L 479.193277 158.569412 L 455.747899 158.569412 z -" clip-path="url(#p93e68949c0)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> +" clip-path="url(#p923f3e33e8)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> @@ -9740,12 +9740,12 @@ L 477.318187 167.349211 L 477.587984 167.344 L 477.857781 167.340926 L 478.127578 167.339918 -" clip-path="url(#p93e68949c0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p923f3e33e8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p923f3e33e8)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9763,7 +9763,7 @@ L 507.327731 177.204706 L 507.327731 158.569412 L 483.882353 158.569412 z -" clip-path="url(#p4e5ed61d79)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> +" clip-path="url(#p2b102c0960)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> @@ -9848,12 +9848,12 @@ L 505.45264 167.335842 L 505.722438 167.338128 L 505.992235 167.339476 L 506.262032 167.339918 -" clip-path="url(#p4e5ed61d79)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2b102c0960)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2b102c0960)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9871,7 +9871,7 @@ L 535.462185 177.204706 L 535.462185 158.569412 L 512.016807 158.569412 z -" clip-path="url(#pde6bd025d9)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> +" clip-path="url(#pf040a10fd5)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> @@ -9956,12 +9956,12 @@ L 533.587094 167.340062 L 533.856891 167.339981 L 534.126689 167.339934 L 534.396486 167.339918 -" clip-path="url(#pde6bd025d9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf040a10fd5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf040a10fd5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9979,7 +9979,7 @@ L 563.596639 177.204706 L 563.596639 158.569412 L 540.151261 158.569412 z -" clip-path="url(#pda3de97b74)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#pb5b606a2d0)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -10064,12 +10064,12 @@ L 561.721548 167.336189 L 561.991345 167.33828 L 562.261142 167.339513 L 562.53094 167.339918 -" clip-path="url(#pda3de97b74)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb5b606a2d0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb5b606a2d0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10087,7 +10087,7 @@ L 591.731092 177.204706 L 591.731092 158.569412 L 568.285714 158.569412 z -" clip-path="url(#pc786f0834a)" style="fill: #1515ff; opacity: 0.5; stroke: #1515ff; stroke-linejoin: miter"/> +" clip-path="url(#p6561dba3ea)" style="fill: #1515ff; opacity: 0.5; stroke: #1515ff; stroke-linejoin: miter"/> @@ -10172,12 +10172,12 @@ L 589.856002 167.355758 L 590.125799 167.346875 L 590.395596 167.341636 L 590.665393 167.339918 -" clip-path="url(#pc786f0834a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6561dba3ea)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6561dba3ea)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10195,7 +10195,7 @@ L 619.865546 177.204706 L 619.865546 158.569412 L 596.420168 158.569412 z -" clip-path="url(#pa3be117fbc)" style="fill: #6d6dff; opacity: 0.5; stroke: #6d6dff; stroke-linejoin: miter"/> +" clip-path="url(#pa70a23ed0f)" style="fill: #6d6dff; opacity: 0.5; stroke: #6d6dff; stroke-linejoin: miter"/> @@ -10280,12 +10280,12 @@ L 617.990456 167.349142 L 618.260253 167.343969 L 618.53005 167.340919 L 618.799847 167.339918 -" clip-path="url(#pa3be117fbc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa70a23ed0f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa70a23ed0f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10303,7 +10303,7 @@ L 113.445378 199.567059 L 113.445378 180.931765 L 90 180.931765 z -" clip-path="url(#p021cd82c03)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#p3dc3d457f1)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -10388,12 +10388,12 @@ L 111.570287 191.985482 L 111.840085 191.985884 L 112.109882 191.986121 L 112.379679 191.986199 -" clip-path="url(#p021cd82c03)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3dc3d457f1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3dc3d457f1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10411,7 +10411,7 @@ L 141.579832 199.567059 L 141.579832 180.931765 L 118.134454 180.931765 z -" clip-path="url(#pb875ceb842)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> +" clip-path="url(#pc4903c3fca)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> @@ -10496,12 +10496,12 @@ L 139.704741 191.977935 L 139.974538 191.982569 L 140.244336 191.985303 L 140.514133 191.986199 -" clip-path="url(#pb875ceb842)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc4903c3fca)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc4903c3fca)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10519,7 +10519,7 @@ L 169.714286 199.567059 L 169.714286 180.931765 L 146.268908 180.931765 z -" clip-path="url(#pd1b6e02e0c)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#p819679df4a)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -10604,12 +10604,12 @@ L 167.839195 191.995921 L 168.108992 191.990469 L 168.378789 191.987254 L 168.648587 191.986199 -" clip-path="url(#pd1b6e02e0c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p819679df4a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p819679df4a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10627,7 +10627,7 @@ L 197.848739 199.567059 L 197.848739 180.931765 L 174.403361 180.931765 z -" clip-path="url(#p7fa91a99a2)" style="fill: #ffc9c9; opacity: 0.5; stroke: #ffc9c9; stroke-linejoin: miter"/> +" clip-path="url(#p93585ebcbc)" style="fill: #ffc9c9; opacity: 0.5; stroke: #ffc9c9; stroke-linejoin: miter"/> @@ -10712,12 +10712,12 @@ L 195.973649 191.977862 L 196.243446 191.982537 L 196.513243 191.985295 L 196.78304 191.986199 -" clip-path="url(#p7fa91a99a2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p93585ebcbc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p93585ebcbc)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10735,7 +10735,7 @@ L 225.983193 199.567059 L 225.983193 180.931765 L 202.537815 180.931765 z -" clip-path="url(#pf0d92b94b3)" style="fill: #ffc5c5; opacity: 0.5; stroke: #ffc5c5; stroke-linejoin: miter"/> +" clip-path="url(#pa376a79194)" style="fill: #ffc5c5; opacity: 0.5; stroke: #ffc5c5; stroke-linejoin: miter"/> @@ -10820,12 +10820,12 @@ L 224.108103 191.979412 L 224.3779 191.983218 L 224.647697 191.985463 L 224.917494 191.986199 -" clip-path="url(#pf0d92b94b3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa376a79194)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa376a79194)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10843,7 +10843,7 @@ L 254.117647 199.567059 L 254.117647 180.931765 L 230.672269 180.931765 z -" clip-path="url(#p3d860f66bf)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p07f3762b20)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -10928,12 +10928,12 @@ L 252.242556 191.965628 L 252.512354 191.977164 L 252.782151 191.983967 L 253.051948 191.986199 -" clip-path="url(#p3d860f66bf)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p07f3762b20)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p07f3762b20)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10951,7 +10951,7 @@ L 282.252101 199.567059 L 282.252101 180.931765 L 258.806723 180.931765 z -" clip-path="url(#p8486e961a2)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> +" clip-path="url(#pcbc52a6c18)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> @@ -11036,12 +11036,12 @@ L 280.37701 191.987483 L 280.646807 191.986763 L 280.916605 191.986338 L 281.186402 191.986199 -" clip-path="url(#p8486e961a2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcbc52a6c18)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcbc52a6c18)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11059,7 +11059,7 @@ L 310.386555 199.567059 L 310.386555 180.931765 L 286.941176 180.931765 z -" clip-path="url(#p46e72157e5)" style="fill: #ffc9c9; opacity: 0.5; stroke: #ffc9c9; stroke-linejoin: miter"/> +" clip-path="url(#p9b6750bd04)" style="fill: #ffc9c9; opacity: 0.5; stroke: #ffc9c9; stroke-linejoin: miter"/> @@ -11144,12 +11144,12 @@ L 308.511464 191.979301 L 308.781261 191.983169 L 309.051058 191.985451 L 309.320856 191.986199 -" clip-path="url(#p46e72157e5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9b6750bd04)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9b6750bd04)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11167,7 +11167,7 @@ L 338.521008 199.567059 L 338.521008 180.931765 L 315.07563 180.931765 z -" clip-path="url(#p15cfc4435c)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> +" clip-path="url(#pe0e6dc86e2)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> @@ -11252,12 +11252,12 @@ L 336.645918 191.975553 L 336.915715 191.981523 L 337.185512 191.985044 L 337.455309 191.986199 -" clip-path="url(#p15cfc4435c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe0e6dc86e2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe0e6dc86e2)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11275,7 +11275,7 @@ L 366.655462 199.567059 L 366.655462 180.931765 L 343.210084 180.931765 z -" clip-path="url(#p1552cb7338)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> +" clip-path="url(#p04c17d9da9)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> @@ -11360,12 +11360,12 @@ L 364.780372 191.98442 L 365.050169 191.985418 L 365.319966 191.986006 L 365.589763 191.986199 -" clip-path="url(#p1552cb7338)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p04c17d9da9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p04c17d9da9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11383,7 +11383,7 @@ L 394.789916 199.567059 L 394.789916 180.931765 L 371.344538 180.931765 z -" clip-path="url(#p10959895b3)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> +" clip-path="url(#pc416a7a754)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> @@ -11468,12 +11468,12 @@ L 392.914825 191.985499 L 393.184623 191.985892 L 393.45442 191.986123 L 393.724217 191.986199 -" clip-path="url(#p10959895b3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc416a7a754)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc416a7a754)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11491,7 +11491,7 @@ L 422.92437 199.567059 L 422.92437 180.931765 L 399.478992 180.931765 z -" clip-path="url(#p78c178d802)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#p2dd7175ad4)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -11576,12 +11576,12 @@ L 421.049279 191.995518 L 421.319076 191.990292 L 421.588874 191.98721 L 421.858671 191.986199 -" clip-path="url(#p78c178d802)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2dd7175ad4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2dd7175ad4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11599,7 +11599,7 @@ L 451.058824 199.567059 L 451.058824 180.931765 L 427.613445 180.931765 z -" clip-path="url(#pe58c915f9e)" style="fill: #8585ff; opacity: 0.5; stroke: #8585ff; stroke-linejoin: miter"/> +" clip-path="url(#pd6321d5c96)" style="fill: #8585ff; opacity: 0.5; stroke: #8585ff; stroke-linejoin: miter"/> @@ -11684,12 +11684,12 @@ L 449.183733 192.007995 L 449.45353 191.995772 L 449.723327 191.988564 L 449.993125 191.986199 -" clip-path="url(#pe58c915f9e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd6321d5c96)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd6321d5c96)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11707,7 +11707,7 @@ L 479.193277 199.567059 L 479.193277 180.931765 L 455.747899 180.931765 z -" clip-path="url(#pfd792c7f2e)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> +" clip-path="url(#p58796f2329)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> @@ -11792,12 +11792,12 @@ L 477.318187 191.990027 L 477.587984 191.98788 L 477.857781 191.986614 L 478.127578 191.986199 -" clip-path="url(#pfd792c7f2e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p58796f2329)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p58796f2329)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11815,7 +11815,7 @@ L 507.327731 199.567059 L 507.327731 180.931765 L 483.882353 180.931765 z -" clip-path="url(#pb53ead9b93)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> +" clip-path="url(#p834822b5b9)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> @@ -11900,12 +11900,12 @@ L 505.45264 191.990307 L 505.722438 191.988003 L 505.992235 191.986645 L 506.262032 191.986199 -" clip-path="url(#pb53ead9b93)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p834822b5b9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p834822b5b9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11923,7 +11923,7 @@ L 535.462185 199.567059 L 535.462185 180.931765 L 512.016807 180.931765 z -" clip-path="url(#p257a024e6d)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#p66d14883ed)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -12008,12 +12008,12 @@ L 533.587094 191.988366 L 533.856891 191.987151 L 534.126689 191.986434 L 534.396486 191.986199 -" clip-path="url(#p257a024e6d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p66d14883ed)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p66d14883ed)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12031,7 +12031,7 @@ L 563.596639 199.567059 L 563.596639 180.931765 L 540.151261 180.931765 z -" clip-path="url(#p304937ca2e)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> +" clip-path="url(#p4872bc1f11)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> @@ -12116,12 +12116,12 @@ L 561.721548 191.996121 L 561.991345 191.990557 L 562.261142 191.987275 L 562.53094 191.986199 -" clip-path="url(#p304937ca2e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4872bc1f11)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4872bc1f11)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12139,7 +12139,7 @@ L 591.731092 199.567059 L 591.731092 180.931765 L 568.285714 180.931765 z -" clip-path="url(#p7b45e722a5)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> +" clip-path="url(#pc1a98399b4)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> @@ -12224,12 +12224,12 @@ L 589.856002 192.003652 L 590.125799 191.993864 L 590.395596 191.988092 L 590.665393 191.986199 -" clip-path="url(#p7b45e722a5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc1a98399b4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc1a98399b4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12247,7 +12247,7 @@ L 619.865546 199.567059 L 619.865546 180.931765 L 596.420168 180.931765 z -" clip-path="url(#pa541e705a3)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p55ce8212df)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -12332,12 +12332,12 @@ L 617.990456 191.994312 L 618.260253 191.989762 L 618.53005 191.987079 L 618.799847 191.986199 -" clip-path="url(#pa541e705a3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p55ce8212df)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p55ce8212df)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12355,7 +12355,7 @@ L 113.445378 221.929412 L 113.445378 203.294118 L 90 203.294118 z -" clip-path="url(#p5b851a4b30)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> +" clip-path="url(#pebadf450d2)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> @@ -12440,12 +12440,12 @@ L 111.570287 213.456812 L 111.840085 213.453205 L 112.109882 213.451078 L 112.379679 213.45038 -" clip-path="url(#p5b851a4b30)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pebadf450d2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pebadf450d2)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12463,7 +12463,7 @@ L 141.579832 221.929412 L 141.579832 203.294118 L 118.134454 203.294118 z -" clip-path="url(#pe33e5ce46a)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> +" clip-path="url(#p8ee54dda3d)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> @@ -12548,12 +12548,12 @@ L 139.704741 213.464813 L 139.974538 213.456719 L 140.244336 213.451946 L 140.514133 213.45038 -" clip-path="url(#pe33e5ce46a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ee54dda3d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ee54dda3d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12571,7 +12571,7 @@ L 169.714286 221.929412 L 169.714286 203.294118 L 146.268908 203.294118 z -" clip-path="url(#p65e0d95035)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> +" clip-path="url(#pe696cf36d6)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> @@ -12656,12 +12656,12 @@ L 167.839195 213.468619 L 168.108992 213.458391 L 168.378789 213.452359 L 168.648587 213.45038 -" clip-path="url(#p65e0d95035)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe696cf36d6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe696cf36d6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12679,7 +12679,7 @@ L 197.848739 221.929412 L 197.848739 203.294118 L 174.403361 203.294118 z -" clip-path="url(#p986e478f11)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> +" clip-path="url(#pf834bcecf6)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> @@ -12764,12 +12764,12 @@ L 195.973649 213.454131 L 196.243446 213.452027 L 196.513243 213.450787 L 196.78304 213.45038 -" clip-path="url(#p986e478f11)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf834bcecf6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf834bcecf6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12787,7 +12787,7 @@ L 225.983193 221.929412 L 225.983193 203.294118 L 202.537815 203.294118 z -" clip-path="url(#p8d7a1996a3)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> +" clip-path="url(#pda83dc9edb)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> @@ -12872,12 +12872,12 @@ L 224.108103 213.434237 L 224.3779 213.44329 L 224.647697 213.448629 L 224.917494 213.45038 -" clip-path="url(#p8d7a1996a3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pda83dc9edb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pda83dc9edb)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12895,7 +12895,7 @@ L 254.117647 221.929412 L 254.117647 203.294118 L 230.672269 203.294118 z -" clip-path="url(#p657021d3ef)" style="fill: #ff7979; opacity: 0.5; stroke: #ff7979; stroke-linejoin: miter"/> +" clip-path="url(#pcb0221e300)" style="fill: #ff7979; opacity: 0.5; stroke: #ff7979; stroke-linejoin: miter"/> @@ -12980,12 +12980,12 @@ L 252.242556 213.423828 L 252.512354 213.438718 L 252.782151 213.4475 L 253.051948 213.45038 -" clip-path="url(#p657021d3ef)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcb0221e300)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcb0221e300)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13003,7 +13003,7 @@ L 282.252101 221.929412 L 282.252101 203.294118 L 258.806723 203.294118 z -" clip-path="url(#pd88eccea27)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#pd72fff589a)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -13088,12 +13088,12 @@ L 280.37701 213.420285 L 280.646807 213.437162 L 280.916605 213.447115 L 281.186402 213.45038 -" clip-path="url(#pd88eccea27)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd72fff589a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd72fff589a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13111,7 +13111,7 @@ L 310.386555 221.929412 L 310.386555 203.294118 L 286.941176 203.294118 z -" clip-path="url(#pb2a7d86254)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> +" clip-path="url(#pe7b9e507ca)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> @@ -13196,12 +13196,12 @@ L 308.511464 213.436931 L 308.781261 213.444473 L 309.051058 213.448921 L 309.320856 213.45038 -" clip-path="url(#pb2a7d86254)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe7b9e507ca)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe7b9e507ca)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13219,7 +13219,7 @@ L 338.521008 221.929412 L 338.521008 203.294118 L 315.07563 203.294118 z -" clip-path="url(#p3166264560)" style="fill: #ff7171; opacity: 0.5; stroke: #ff7171; stroke-linejoin: miter"/> +" clip-path="url(#pd70db8b0dc)" style="fill: #ff7171; opacity: 0.5; stroke: #ff7171; stroke-linejoin: miter"/> @@ -13304,12 +13304,12 @@ L 336.645918 213.421942 L 336.915715 213.43789 L 337.185512 213.447295 L 337.455309 213.45038 -" clip-path="url(#p3166264560)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd70db8b0dc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd70db8b0dc)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13327,7 +13327,7 @@ L 366.655462 221.929412 L 366.655462 203.294118 L 343.210084 203.294118 z -" clip-path="url(#p9ccf1d47b4)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> +" clip-path="url(#pbeb2fa0cd4)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> @@ -13412,12 +13412,12 @@ L 364.780372 213.455306 L 365.050169 213.452543 L 365.319966 213.450914 L 365.589763 213.45038 -" clip-path="url(#p9ccf1d47b4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbeb2fa0cd4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbeb2fa0cd4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13435,7 +13435,7 @@ L 394.789916 221.929412 L 394.789916 203.294118 L 371.344538 203.294118 z -" clip-path="url(#p71f4cbcb7e)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> +" clip-path="url(#p53239a1130)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> @@ -13520,12 +13520,12 @@ L 392.914825 213.43368 L 393.184623 213.443045 L 393.45442 213.448568 L 393.724217 213.45038 -" clip-path="url(#p71f4cbcb7e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p53239a1130)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p53239a1130)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13543,7 +13543,7 @@ L 422.92437 221.929412 L 422.92437 203.294118 L 399.478992 203.294118 z -" clip-path="url(#p61e1467f82)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> +" clip-path="url(#p5f416eae9d)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> @@ -13628,12 +13628,12 @@ L 421.049279 213.457534 L 421.319076 213.453522 L 421.588874 213.451156 L 421.858671 213.45038 -" clip-path="url(#p61e1467f82)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5f416eae9d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5f416eae9d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13651,7 +13651,7 @@ L 451.058824 221.929412 L 451.058824 203.294118 L 427.613445 203.294118 z -" clip-path="url(#p2d22d2b851)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p5b187be363)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -13736,12 +13736,12 @@ L 449.183733 213.447705 L 449.45353 213.449205 L 449.723327 213.45009 L 449.993125 213.45038 -" clip-path="url(#p2d22d2b851)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5b187be363)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5b187be363)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13759,7 +13759,7 @@ L 479.193277 221.929412 L 479.193277 203.294118 L 455.747899 203.294118 z -" clip-path="url(#pce6f22d3a2)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> +" clip-path="url(#pcacb69f336)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> @@ -13844,12 +13844,12 @@ L 477.318187 213.437091 L 477.587984 213.444543 L 477.857781 213.448938 L 478.127578 213.45038 -" clip-path="url(#pce6f22d3a2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcacb69f336)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcacb69f336)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13867,7 +13867,7 @@ L 507.327731 221.929412 L 507.327731 203.294118 L 483.882353 203.294118 z -" clip-path="url(#pa0e9ecb688)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p00510fe8f1)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -13952,12 +13952,12 @@ L 505.45264 213.45532 L 505.722438 213.45255 L 505.992235 213.450916 L 506.262032 213.45038 -" clip-path="url(#pa0e9ecb688)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p00510fe8f1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p00510fe8f1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13975,7 +13975,7 @@ L 535.462185 221.929412 L 535.462185 203.294118 L 512.016807 203.294118 z -" clip-path="url(#pa2d3c51202)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> +" clip-path="url(#p44906ff351)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> @@ -14060,12 +14060,12 @@ L 533.587094 213.443344 L 533.856891 213.44729 L 534.126689 213.449617 L 534.396486 213.45038 -" clip-path="url(#pa2d3c51202)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p44906ff351)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p44906ff351)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14083,7 +14083,7 @@ L 563.596639 221.929412 L 563.596639 203.294118 L 540.151261 203.294118 z -" clip-path="url(#p4761a53a8a)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> +" clip-path="url(#pf8f4518997)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> @@ -14168,12 +14168,12 @@ L 561.721548 213.445931 L 561.991345 213.448426 L 562.261142 213.449898 L 562.53094 213.45038 -" clip-path="url(#p4761a53a8a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf8f4518997)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf8f4518997)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14191,7 +14191,7 @@ L 591.731092 221.929412 L 591.731092 203.294118 L 568.285714 203.294118 z -" clip-path="url(#pc6951b93b0)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> +" clip-path="url(#pd56128005f)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> @@ -14276,12 +14276,12 @@ L 589.856002 213.476501 L 590.125799 213.461852 L 590.395596 213.453214 L 590.665393 213.45038 -" clip-path="url(#pc6951b93b0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd56128005f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd56128005f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14299,7 +14299,7 @@ L 619.865546 221.929412 L 619.865546 203.294118 L 596.420168 203.294118 z -" clip-path="url(#p9958381934)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> +" clip-path="url(#p49e554c618)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> @@ -14384,12 +14384,12 @@ L 617.990456 213.464603 L 618.260253 213.456627 L 618.53005 213.451923 L 618.799847 213.45038 -" clip-path="url(#p9958381934)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p49e554c618)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p49e554c618)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14407,7 +14407,7 @@ L 113.445378 244.291765 L 113.445378 225.656471 L 90 225.656471 z -" clip-path="url(#p169a929c85)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> +" clip-path="url(#p4deef4c670)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> @@ -14492,12 +14492,12 @@ L 111.570287 236.692764 L 111.840085 236.68187 L 112.109882 236.675446 L 112.379679 236.673339 -" clip-path="url(#p169a929c85)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4deef4c670)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4deef4c670)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14515,7 +14515,7 @@ L 141.579832 244.291765 L 141.579832 225.656471 L 118.134454 225.656471 z -" clip-path="url(#p097755502f)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#p6c1f37fb03)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -14600,12 +14600,12 @@ L 139.704741 236.677595 L 139.974538 236.675208 L 140.244336 236.673801 L 140.514133 236.673339 -" clip-path="url(#p097755502f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6c1f37fb03)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6c1f37fb03)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14623,7 +14623,7 @@ L 169.714286 244.291765 L 169.714286 225.656471 L 146.268908 225.656471 z -" clip-path="url(#p30bae80d5d)" style="fill: #adadff; opacity: 0.5; stroke: #adadff; stroke-linejoin: miter"/> +" clip-path="url(#pde50286969)" style="fill: #adadff; opacity: 0.5; stroke: #adadff; stroke-linejoin: miter"/> @@ -14708,12 +14708,12 @@ L 167.839195 236.68623 L 168.108992 236.679001 L 168.378789 236.674737 L 168.648587 236.673339 -" clip-path="url(#p30bae80d5d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pde50286969)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pde50286969)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14731,7 +14731,7 @@ L 197.848739 244.291765 L 197.848739 225.656471 L 174.403361 225.656471 z -" clip-path="url(#pae8991dd53)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> +" clip-path="url(#p8ae0c06f23)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> @@ -14816,12 +14816,12 @@ L 195.973649 236.683315 L 196.243446 236.67772 L 196.513243 236.674421 L 196.78304 236.673339 -" clip-path="url(#pae8991dd53)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ae0c06f23)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ae0c06f23)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14839,7 +14839,7 @@ L 225.983193 244.291765 L 225.983193 225.656471 L 202.537815 225.656471 z -" clip-path="url(#p9936af7547)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> +" clip-path="url(#p4db18ff7a1)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> @@ -14924,12 +14924,12 @@ L 224.108103 236.661119 L 224.3779 236.667972 L 224.647697 236.672013 L 224.917494 236.673339 -" clip-path="url(#p9936af7547)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4db18ff7a1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4db18ff7a1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14947,7 +14947,7 @@ L 254.117647 244.291765 L 254.117647 225.656471 L 230.672269 225.656471 z -" clip-path="url(#pf5c7df3391)" style="fill: #ff8989; opacity: 0.5; stroke: #ff8989; stroke-linejoin: miter"/> +" clip-path="url(#p5a6e50e221)" style="fill: #ff8989; opacity: 0.5; stroke: #ff8989; stroke-linejoin: miter"/> @@ -15032,12 +15032,12 @@ L 252.242556 236.645112 L 252.512354 236.660942 L 252.782151 236.670277 L 253.051948 236.673339 -" clip-path="url(#pf5c7df3391)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5a6e50e221)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5a6e50e221)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15055,7 +15055,7 @@ L 282.252101 244.291765 L 282.252101 225.656471 L 258.806723 225.656471 z -" clip-path="url(#p365ce6389b)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> +" clip-path="url(#p53fbf33eeb)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> @@ -15140,12 +15140,12 @@ L 280.37701 236.659538 L 280.646807 236.667277 L 280.916605 236.671842 L 281.186402 236.673339 -" clip-path="url(#p365ce6389b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p53fbf33eeb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p53fbf33eeb)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15163,7 +15163,7 @@ L 310.386555 244.291765 L 310.386555 225.656471 L 286.941176 225.656471 z -" clip-path="url(#p6c3e2fcf4a)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#pf7a269545d)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -15248,12 +15248,12 @@ L 308.511464 236.641078 L 308.781261 236.65917 L 309.051058 236.669839 L 309.320856 236.673339 -" clip-path="url(#p6c3e2fcf4a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf7a269545d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf7a269545d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15271,7 +15271,7 @@ L 338.521008 244.291765 L 338.521008 225.656471 L 315.07563 225.656471 z -" clip-path="url(#pd5ab3e846a)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> +" clip-path="url(#p4406b45992)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> @@ -15356,12 +15356,12 @@ L 336.645918 236.652804 L 336.915715 236.66432 L 337.185512 236.671111 L 337.455309 236.673339 -" clip-path="url(#pd5ab3e846a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4406b45992)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4406b45992)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15379,7 +15379,7 @@ L 366.655462 244.291765 L 366.655462 225.656471 L 343.210084 225.656471 z -" clip-path="url(#p6e5917034b)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> +" clip-path="url(#p321d1dff4b)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> @@ -15464,12 +15464,12 @@ L 364.780372 236.669554 L 365.050169 236.671676 L 365.319966 236.672928 L 365.589763 236.673339 -" clip-path="url(#p6e5917034b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p321d1dff4b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p321d1dff4b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15487,7 +15487,7 @@ L 394.789916 244.291765 L 394.789916 225.656471 L 371.344538 225.656471 z -" clip-path="url(#pc732c08285)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> +" clip-path="url(#p61814c0ab5)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> @@ -15572,12 +15572,12 @@ L 392.914825 236.666624 L 393.184623 236.67039 L 393.45442 236.67261 L 393.724217 236.673339 -" clip-path="url(#pc732c08285)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p61814c0ab5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p61814c0ab5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15595,7 +15595,7 @@ L 422.92437 244.291765 L 422.92437 225.656471 L 399.478992 225.656471 z -" clip-path="url(#p5d8dc2c116)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#p50ebf97e10)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -15680,12 +15680,12 @@ L 421.049279 236.671131 L 421.319076 236.672369 L 421.588874 236.673099 L 421.858671 236.673339 -" clip-path="url(#p5d8dc2c116)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p50ebf97e10)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p50ebf97e10)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15703,7 +15703,7 @@ L 451.058824 244.291765 L 451.058824 225.656471 L 427.613445 225.656471 z -" clip-path="url(#p699eb87899)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> +" clip-path="url(#pba83e3944c)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> @@ -15788,12 +15788,12 @@ L 449.183733 236.68525 L 449.45353 236.67857 L 449.723327 236.674631 L 449.993125 236.673339 -" clip-path="url(#p699eb87899)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pba83e3944c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pba83e3944c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15811,7 +15811,7 @@ L 479.193277 244.291765 L 479.193277 225.656471 L 455.747899 225.656471 z -" clip-path="url(#p56be419a4c)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> +" clip-path="url(#pef9decf78d)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> @@ -15896,12 +15896,12 @@ L 477.318187 236.671734 L 477.587984 236.672634 L 477.857781 236.673165 L 478.127578 236.673339 -" clip-path="url(#p56be419a4c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pef9decf78d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pef9decf78d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15919,7 +15919,7 @@ L 507.327731 244.291765 L 507.327731 225.656471 L 483.882353 225.656471 z -" clip-path="url(#p2ca32f3500)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> +" clip-path="url(#p86fbeef7d1)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> @@ -16004,12 +16004,12 @@ L 505.45264 236.678984 L 505.722438 236.675818 L 505.992235 236.673951 L 506.262032 236.673339 -" clip-path="url(#p2ca32f3500)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p86fbeef7d1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p86fbeef7d1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16027,7 +16027,7 @@ L 535.462185 244.291765 L 535.462185 225.656471 L 512.016807 225.656471 z -" clip-path="url(#pe9b51270ea)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> +" clip-path="url(#pb1d2c54a53)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> @@ -16112,12 +16112,12 @@ L 533.587094 236.664773 L 533.856891 236.669577 L 534.126689 236.67241 L 534.396486 236.673339 -" clip-path="url(#pe9b51270ea)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb1d2c54a53)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb1d2c54a53)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16135,7 +16135,7 @@ L 563.596639 244.291765 L 563.596639 225.656471 L 540.151261 225.656471 z -" clip-path="url(#pa41e06765d)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#paff936fc9a)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -16220,12 +16220,12 @@ L 561.721548 236.673188 L 561.991345 236.673273 L 562.261142 236.673323 L 562.53094 236.673339 -" clip-path="url(#pa41e06765d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paff936fc9a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paff936fc9a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16243,7 +16243,7 @@ L 591.731092 244.291765 L 591.731092 225.656471 L 568.285714 225.656471 z -" clip-path="url(#pe26440a59e)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> +" clip-path="url(#p9af55b7d3e)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> @@ -16328,12 +16328,12 @@ L 589.856002 236.695308 L 590.125799 236.682988 L 590.395596 236.675722 L 590.665393 236.673339 -" clip-path="url(#pe26440a59e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9af55b7d3e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9af55b7d3e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16351,7 +16351,7 @@ L 619.865546 244.291765 L 619.865546 225.656471 L 596.420168 225.656471 z -" clip-path="url(#p24c067b095)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p6d0a13549b)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -16436,12 +16436,12 @@ L 617.990456 236.680774 L 618.260253 236.676605 L 618.53005 236.674146 L 618.799847 236.673339 -" clip-path="url(#p24c067b095)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6d0a13549b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6d0a13549b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16459,7 +16459,7 @@ L 113.445378 266.654118 L 113.445378 248.018824 L 90 248.018824 z -" clip-path="url(#p8dcad32f10)" style="fill: #6565ff; opacity: 0.5; stroke: #6565ff; stroke-linejoin: miter"/> +" clip-path="url(#pec4475b9b0)" style="fill: #6565ff; opacity: 0.5; stroke: #6565ff; stroke-linejoin: miter"/> @@ -16544,12 +16544,12 @@ L 111.570287 257.534332 L 111.840085 257.52298 L 112.109882 257.516286 L 112.379679 257.51409 -" clip-path="url(#p8dcad32f10)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pec4475b9b0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pec4475b9b0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16567,7 +16567,7 @@ L 141.579832 266.654118 L 141.579832 248.018824 L 118.134454 248.018824 z -" clip-path="url(#p2261cbb452)" style="fill: #ffb1b1; opacity: 0.5; stroke: #ffb1b1; stroke-linejoin: miter"/> +" clip-path="url(#pef4a17bdf0)" style="fill: #ffb1b1; opacity: 0.5; stroke: #ffb1b1; stroke-linejoin: miter"/> @@ -16652,12 +16652,12 @@ L 139.704741 257.502514 L 139.974538 257.509006 L 140.244336 257.512834 L 140.514133 257.51409 -" clip-path="url(#p2261cbb452)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pef4a17bdf0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pef4a17bdf0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16675,7 +16675,7 @@ L 169.714286 266.654118 L 169.714286 248.018824 L 146.268908 248.018824 z -" clip-path="url(#p893b2742c9)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> +" clip-path="url(#paf9e17cf16)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> @@ -16760,12 +16760,12 @@ L 167.839195 257.520305 L 168.108992 257.516819 L 168.378789 257.514764 L 168.648587 257.51409 -" clip-path="url(#p893b2742c9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paf9e17cf16)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paf9e17cf16)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16783,7 +16783,7 @@ L 197.848739 266.654118 L 197.848739 248.018824 L 174.403361 248.018824 z -" clip-path="url(#p0216f460b1)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> +" clip-path="url(#p683a664ec4)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> @@ -16868,12 +16868,12 @@ L 195.973649 257.523118 L 196.243446 257.518055 L 196.513243 257.515069 L 196.78304 257.51409 -" clip-path="url(#p0216f460b1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p683a664ec4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p683a664ec4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16891,7 +16891,7 @@ L 225.983193 266.654118 L 225.983193 248.018824 L 202.537815 248.018824 z -" clip-path="url(#pfc9da674fe)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#pe80ac3be76)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -16976,12 +16976,12 @@ L 224.108103 257.504542 L 224.3779 257.509896 L 224.647697 257.513054 L 224.917494 257.51409 -" clip-path="url(#pfc9da674fe)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe80ac3be76)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe80ac3be76)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16999,7 +16999,7 @@ L 254.117647 266.654118 L 254.117647 248.018824 L 230.672269 248.018824 z -" clip-path="url(#pb45d1bdb16)" style="fill: #ffb9b9; opacity: 0.5; stroke: #ffb9b9; stroke-linejoin: miter"/> +" clip-path="url(#p7d8bf6b7cf)" style="fill: #ffb9b9; opacity: 0.5; stroke: #ffb9b9; stroke-linejoin: miter"/> @@ -17084,12 +17084,12 @@ L 252.242556 257.490451 L 252.512354 257.503707 L 252.782151 257.511525 L 253.051948 257.51409 -" clip-path="url(#pb45d1bdb16)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7d8bf6b7cf)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7d8bf6b7cf)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17107,7 +17107,7 @@ L 282.252101 266.654118 L 282.252101 248.018824 L 258.806723 248.018824 z -" clip-path="url(#p79c12aad27)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> +" clip-path="url(#p7cf3a23499)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> @@ -17192,12 +17192,12 @@ L 280.37701 257.507306 L 280.646807 257.51111 L 280.916605 257.513354 L 281.186402 257.51409 -" clip-path="url(#p79c12aad27)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7cf3a23499)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7cf3a23499)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17215,7 +17215,7 @@ L 310.386555 266.654118 L 310.386555 248.018824 L 286.941176 248.018824 z -" clip-path="url(#p6695d3f306)" style="fill: #ff6d6d; opacity: 0.5; stroke: #ff6d6d; stroke-linejoin: miter"/> +" clip-path="url(#p344d3fb5b8)" style="fill: #ff6d6d; opacity: 0.5; stroke: #ff6d6d; stroke-linejoin: miter"/> @@ -17300,12 +17300,12 @@ L 308.511464 257.492572 L 308.781261 257.504639 L 309.051058 257.511755 L 309.320856 257.51409 -" clip-path="url(#p6695d3f306)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p344d3fb5b8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p344d3fb5b8)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17323,7 +17323,7 @@ L 338.521008 266.654118 L 338.521008 248.018824 L 315.07563 248.018824 z -" clip-path="url(#p1623733752)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p2c569de72b)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -17408,12 +17408,12 @@ L 336.645918 257.496544 L 336.915715 257.506384 L 337.185512 257.512186 L 337.455309 257.51409 -" clip-path="url(#p1623733752)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2c569de72b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2c569de72b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17431,7 +17431,7 @@ L 366.655462 266.654118 L 366.655462 248.018824 L 343.210084 248.018824 z -" clip-path="url(#pb0acab58d6)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> +" clip-path="url(#p4e7368d6a5)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> @@ -17516,12 +17516,12 @@ L 364.780372 257.527932 L 365.050169 257.520169 L 365.319966 257.515591 L 365.589763 257.51409 -" clip-path="url(#pb0acab58d6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4e7368d6a5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4e7368d6a5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17539,7 +17539,7 @@ L 394.789916 266.654118 L 394.789916 248.018824 L 371.344538 248.018824 z -" clip-path="url(#pa1dd1c51e8)" style="fill: #ffbdbd; opacity: 0.5; stroke: #ffbdbd; stroke-linejoin: miter"/> +" clip-path="url(#pc4a02d09e3)" style="fill: #ffbdbd; opacity: 0.5; stroke: #ffbdbd; stroke-linejoin: miter"/> @@ -17624,12 +17624,12 @@ L 392.914825 257.506353 L 393.184623 257.510692 L 393.45442 257.51325 L 393.724217 257.51409 -" clip-path="url(#pa1dd1c51e8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc4a02d09e3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc4a02d09e3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17647,7 +17647,7 @@ L 422.92437 266.654118 L 422.92437 248.018824 L 399.478992 248.018824 z -" clip-path="url(#p494ea5f514)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> +" clip-path="url(#pb5d40d3c80)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> @@ -17732,12 +17732,12 @@ L 421.049279 257.515663 L 421.319076 257.514781 L 421.588874 257.51426 L 421.858671 257.51409 -" clip-path="url(#p494ea5f514)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb5d40d3c80)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb5d40d3c80)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17755,7 +17755,7 @@ L 451.058824 266.654118 L 451.058824 248.018824 L 427.613445 248.018824 z -" clip-path="url(#p04e15785dc)" style="fill: #9595ff; opacity: 0.5; stroke: #9595ff; stroke-linejoin: miter"/> +" clip-path="url(#p4aa3523ec1)" style="fill: #9595ff; opacity: 0.5; stroke: #9595ff; stroke-linejoin: miter"/> @@ -17840,12 +17840,12 @@ L 449.183733 257.518347 L 449.45353 257.515959 L 449.723327 257.514552 L 449.993125 257.51409 -" clip-path="url(#p04e15785dc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4aa3523ec1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4aa3523ec1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17863,7 +17863,7 @@ L 479.193277 266.654118 L 479.193277 248.018824 L 455.747899 248.018824 z -" clip-path="url(#pb1ae75497e)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> +" clip-path="url(#p649052f78f)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> @@ -17948,12 +17948,12 @@ L 477.318187 257.515027 L 477.587984 257.514501 L 477.857781 257.514191 L 478.127578 257.51409 -" clip-path="url(#pb1ae75497e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p649052f78f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p649052f78f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17971,7 +17971,7 @@ L 507.327731 266.654118 L 507.327731 248.018824 L 483.882353 248.018824 z -" clip-path="url(#p28840b3a41)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> +" clip-path="url(#pb6d126db1c)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> @@ -18056,12 +18056,12 @@ L 505.45264 257.523423 L 505.722438 257.518189 L 505.992235 257.515102 L 506.262032 257.51409 -" clip-path="url(#p28840b3a41)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb6d126db1c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb6d126db1c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18079,7 +18079,7 @@ L 535.462185 266.654118 L 535.462185 248.018824 L 512.016807 248.018824 z -" clip-path="url(#p1f3d8f83d0)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> +" clip-path="url(#p9aad5f6fac)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> @@ -18164,12 +18164,12 @@ L 533.587094 257.509686 L 533.856891 257.512155 L 534.126689 257.513612 L 534.396486 257.51409 -" clip-path="url(#p1f3d8f83d0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9aad5f6fac)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9aad5f6fac)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18187,7 +18187,7 @@ L 563.596639 266.654118 L 563.596639 248.018824 L 540.151261 248.018824 z -" clip-path="url(#p26b9101078)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p6c4e0ecda7)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -18272,12 +18272,12 @@ L 561.721548 257.514644 L 561.991345 257.514333 L 562.261142 257.51415 L 562.53094 257.51409 -" clip-path="url(#p26b9101078)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6c4e0ecda7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6c4e0ecda7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18295,7 +18295,7 @@ L 591.731092 266.654118 L 591.731092 248.018824 L 568.285714 248.018824 z -" clip-path="url(#p74415eaf6f)" style="fill: #7d7dff; opacity: 0.5; stroke: #7d7dff; stroke-linejoin: miter"/> +" clip-path="url(#p2a57e6503b)" style="fill: #7d7dff; opacity: 0.5; stroke: #7d7dff; stroke-linejoin: miter"/> @@ -18380,12 +18380,12 @@ L 589.856002 257.537397 L 590.125799 257.524326 L 590.395596 257.516618 L 590.665393 257.51409 -" clip-path="url(#p74415eaf6f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2a57e6503b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2a57e6503b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18403,7 +18403,7 @@ L 619.865546 266.654118 L 619.865546 248.018824 L 596.420168 248.018824 z -" clip-path="url(#p13b19d2359)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> +" clip-path="url(#p68cc10715d)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> @@ -18488,12 +18488,12 @@ L 617.990456 257.52 L 618.260253 257.516686 L 618.53005 257.514731 L 618.799847 257.51409 -" clip-path="url(#p13b19d2359)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p68cc10715d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p68cc10715d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18511,7 +18511,7 @@ L 113.445378 289.016471 L 113.445378 270.381176 L 90 270.381176 z -" clip-path="url(#pd689110c07)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> +" clip-path="url(#pe04c197eea)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> @@ -18700,12 +18700,12 @@ L 111.570287 279.921851 L 111.840085 279.916215 L 112.109882 279.912891 L 112.379679 279.9118 -" clip-path="url(#pd689110c07)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe04c197eea)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe04c197eea)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18723,7 +18723,7 @@ L 141.579832 289.016471 L 141.579832 270.381176 L 118.134454 270.381176 z -" clip-path="url(#pd39633e402)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> +" clip-path="url(#p5ea1647dae)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> @@ -18808,12 +18808,12 @@ L 139.704741 279.905144 L 139.974538 279.908877 L 140.244336 279.911078 L 140.514133 279.9118 -" clip-path="url(#pd39633e402)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5ea1647dae)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5ea1647dae)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18831,7 +18831,7 @@ L 169.714286 289.016471 L 169.714286 270.381176 L 146.268908 270.381176 z -" clip-path="url(#pf1e37fe3d7)" style="fill: #3d3dff; opacity: 0.5; stroke: #3d3dff; stroke-linejoin: miter"/> +" clip-path="url(#paee30fa030)" style="fill: #3d3dff; opacity: 0.5; stroke: #3d3dff; stroke-linejoin: miter"/> @@ -18916,12 +18916,12 @@ L 167.839195 279.922655 L 168.108992 279.916568 L 168.378789 279.912978 L 168.648587 279.9118 -" clip-path="url(#pf1e37fe3d7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paee30fa030)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paee30fa030)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18939,7 +18939,7 @@ L 197.848739 289.016471 L 197.848739 270.381176 L 174.403361 270.381176 z -" clip-path="url(#p0f190717d9)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> +" clip-path="url(#pcb6ad6337e)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> @@ -19024,12 +19024,12 @@ L 195.973649 279.916278 L 196.243446 279.913767 L 196.513243 279.912286 L 196.78304 279.9118 -" clip-path="url(#p0f190717d9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcb6ad6337e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcb6ad6337e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19047,7 +19047,7 @@ L 225.983193 289.016471 L 225.983193 270.381176 L 202.537815 270.381176 z -" clip-path="url(#p93715b46cf)" style="fill: #7171ff; opacity: 0.5; stroke: #7171ff; stroke-linejoin: miter"/> +" clip-path="url(#p2a8ff50885)" style="fill: #7171ff; opacity: 0.5; stroke: #7171ff; stroke-linejoin: miter"/> @@ -19132,12 +19132,12 @@ L 224.108103 279.919405 L 224.3779 279.91514 L 224.647697 279.912625 L 224.917494 279.9118 -" clip-path="url(#p93715b46cf)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2a8ff50885)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2a8ff50885)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19155,7 +19155,7 @@ L 254.117647 289.016471 L 254.117647 270.381176 L 230.672269 270.381176 z -" clip-path="url(#p51e85e92c6)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> +" clip-path="url(#pdb575af27d)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> @@ -19240,12 +19240,12 @@ L 252.242556 279.90632 L 252.512354 279.909393 L 252.782151 279.911206 L 253.051948 279.9118 -" clip-path="url(#p51e85e92c6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdb575af27d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdb575af27d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19263,7 +19263,7 @@ L 282.252101 289.016471 L 282.252101 270.381176 L 258.806723 270.381176 z -" clip-path="url(#p803617f84a)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p4e14353a8a)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -19348,12 +19348,12 @@ L 280.37701 279.91682 L 280.646807 279.914005 L 280.916605 279.912345 L 281.186402 279.9118 -" clip-path="url(#p803617f84a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4e14353a8a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4e14353a8a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19371,7 +19371,7 @@ L 310.386555 289.016471 L 310.386555 270.381176 L 286.941176 270.381176 z -" clip-path="url(#p769d05841c)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> +" clip-path="url(#pba212a21cb)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> @@ -19456,12 +19456,12 @@ L 308.511464 279.903943 L 308.781261 279.908349 L 309.051058 279.910948 L 309.320856 279.9118 -" clip-path="url(#p769d05841c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pba212a21cb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pba212a21cb)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19479,7 +19479,7 @@ L 338.521008 289.016471 L 338.521008 270.381176 L 315.07563 270.381176 z -" clip-path="url(#pb89900e586)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p09704fe87b)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -19564,12 +19564,12 @@ L 336.645918 279.899982 L 336.915715 279.90661 L 337.185512 279.910518 L 337.455309 279.9118 -" clip-path="url(#pb89900e586)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p09704fe87b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p09704fe87b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19587,7 +19587,7 @@ L 366.655462 289.016471 L 366.655462 270.381176 L 343.210084 270.381176 z -" clip-path="url(#p98b85104e0)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p96d39ac743)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -19672,12 +19672,12 @@ L 364.780372 279.914681 L 365.050169 279.913066 L 365.319966 279.912113 L 365.589763 279.9118 -" clip-path="url(#p98b85104e0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p96d39ac743)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p96d39ac743)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19695,7 +19695,7 @@ L 394.789916 289.016471 L 394.789916 270.381176 L 371.344538 270.381176 z -" clip-path="url(#p4353aa2a27)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> +" clip-path="url(#p657bb364e8)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> @@ -19780,12 +19780,12 @@ L 392.914825 279.911205 L 393.184623 279.911539 L 393.45442 279.911736 L 393.724217 279.9118 -" clip-path="url(#p4353aa2a27)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p657bb364e8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p657bb364e8)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19803,7 +19803,7 @@ L 422.92437 289.016471 L 422.92437 270.381176 L 399.478992 270.381176 z -" clip-path="url(#pf4789c4823)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> +" clip-path="url(#pe8037f7c46)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> @@ -19888,12 +19888,12 @@ L 421.049279 279.907792 L 421.319076 279.91004 L 421.588874 279.911366 L 421.858671 279.9118 -" clip-path="url(#pf4789c4823)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe8037f7c46)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe8037f7c46)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19911,7 +19911,7 @@ L 451.058824 289.016471 L 451.058824 270.381176 L 427.613445 270.381176 z -" clip-path="url(#p4e8c82aff9)" style="fill: #8585ff; opacity: 0.5; stroke: #8585ff; stroke-linejoin: miter"/> +" clip-path="url(#pd1610bda9a)" style="fill: #8585ff; opacity: 0.5; stroke: #8585ff; stroke-linejoin: miter"/> @@ -19996,12 +19996,12 @@ L 449.183733 279.918591 L 449.45353 279.914783 L 449.723327 279.912537 L 449.993125 279.9118 -" clip-path="url(#p4e8c82aff9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd1610bda9a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd1610bda9a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20019,7 +20019,7 @@ L 479.193277 289.016471 L 479.193277 270.381176 L 455.747899 270.381176 z -" clip-path="url(#p1ca7f637e6)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> +" clip-path="url(#p3e5e01f6f7)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> @@ -20104,12 +20104,12 @@ L 477.318187 279.904075 L 477.587984 279.908407 L 477.857781 279.910962 L 478.127578 279.9118 -" clip-path="url(#p1ca7f637e6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3e5e01f6f7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3e5e01f6f7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20127,7 +20127,7 @@ L 507.327731 289.016471 L 507.327731 270.381176 L 483.882353 270.381176 z -" clip-path="url(#pe67a9c4e66)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> +" clip-path="url(#p72426f9a9e)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> @@ -20212,12 +20212,12 @@ L 505.45264 279.914063 L 505.722438 279.912794 L 505.992235 279.912046 L 506.262032 279.9118 -" clip-path="url(#pe67a9c4e66)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p72426f9a9e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p72426f9a9e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20235,7 +20235,7 @@ L 535.462185 289.016471 L 535.462185 270.381176 L 512.016807 270.381176 z -" clip-path="url(#p5f097ece06)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> +" clip-path="url(#p21ebc72e2c)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> @@ -20320,12 +20320,12 @@ L 533.587094 279.908496 L 533.856891 279.910349 L 534.126689 279.911442 L 534.396486 279.9118 -" clip-path="url(#p5f097ece06)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p21ebc72e2c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p21ebc72e2c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20343,7 +20343,7 @@ L 563.596639 289.016471 L 563.596639 270.381176 L 540.151261 270.381176 z -" clip-path="url(#p0ac198ccf9)" style="fill: #adadff; opacity: 0.5; stroke: #adadff; stroke-linejoin: miter"/> +" clip-path="url(#pc63c7174f5)" style="fill: #adadff; opacity: 0.5; stroke: #adadff; stroke-linejoin: miter"/> @@ -20428,12 +20428,12 @@ L 561.721548 279.909286 L 561.991345 279.910696 L 562.261142 279.911528 L 562.53094 279.9118 -" clip-path="url(#p0ac198ccf9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc63c7174f5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc63c7174f5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20451,7 +20451,7 @@ L 591.731092 289.016471 L 591.731092 270.381176 L 568.285714 270.381176 z -" clip-path="url(#p384b71cb83)" style="fill: #0000d0; opacity: 0.5; stroke: #0000d0; stroke-linejoin: miter"/> +" clip-path="url(#p7b270a76ea)" style="fill: #0000d0; opacity: 0.5; stroke: #0000d0; stroke-linejoin: miter"/> @@ -20536,12 +20536,12 @@ L 589.856002 279.938338 L 590.125799 279.923456 L 590.395596 279.914679 L 590.665393 279.9118 -" clip-path="url(#p384b71cb83)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7b270a76ea)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7b270a76ea)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20559,7 +20559,7 @@ L 619.865546 289.016471 L 619.865546 270.381176 L 596.420168 270.381176 z -" clip-path="url(#p2f57205f3c)" style="fill: #6969ff; opacity: 0.5; stroke: #6969ff; stroke-linejoin: miter"/> +" clip-path="url(#pc1b46ce49a)" style="fill: #6969ff; opacity: 0.5; stroke: #6969ff; stroke-linejoin: miter"/> @@ -20644,12 +20644,12 @@ L 617.990456 279.923673 L 618.260253 279.917015 L 618.53005 279.913088 L 618.799847 279.9118 -" clip-path="url(#p2f57205f3c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc1b46ce49a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc1b46ce49a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20667,7 +20667,7 @@ L 113.445378 311.378824 L 113.445378 292.743529 L 90 292.743529 z -" clip-path="url(#p34af66d8fe)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#pdf646a17f7)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -20752,12 +20752,12 @@ L 111.570287 301.001916 L 111.840085 300.997827 L 112.109882 300.995415 L 112.379679 300.994624 -" clip-path="url(#p34af66d8fe)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdf646a17f7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdf646a17f7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20775,7 +20775,7 @@ L 141.579832 311.378824 L 141.579832 292.743529 L 118.134454 292.743529 z -" clip-path="url(#p9dc423476a)" style="fill: #fffdfd; opacity: 0.5; stroke: #fffdfd; stroke-linejoin: miter"/> +" clip-path="url(#p26ddb42120)" style="fill: #fffdfd; opacity: 0.5; stroke: #fffdfd; stroke-linejoin: miter"/> @@ -20860,12 +20860,12 @@ L 139.704741 300.991346 L 139.974538 300.993185 L 140.244336 300.994269 L 140.514133 300.994624 -" clip-path="url(#p9dc423476a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p26ddb42120)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p26ddb42120)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20883,7 +20883,7 @@ L 169.714286 311.378824 L 169.714286 292.743529 L 146.268908 292.743529 z -" clip-path="url(#p643e0a1be3)" style="fill: #0000b4; opacity: 0.5; stroke: #0000b4; stroke-linejoin: miter"/> +" clip-path="url(#pd9472a5a86)" style="fill: #0000b4; opacity: 0.5; stroke: #0000b4; stroke-linejoin: miter"/> @@ -20968,12 +20968,12 @@ L 167.839195 301.010657 L 168.108992 301.001666 L 168.378789 300.996364 L 168.648587 300.994624 -" clip-path="url(#p643e0a1be3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd9472a5a86)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd9472a5a86)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20991,7 +20991,7 @@ L 197.848739 311.378824 L 197.848739 292.743529 L 174.403361 292.743529 z -" clip-path="url(#p1141eee0a5)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> +" clip-path="url(#p9737bb1b89)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> @@ -21076,12 +21076,12 @@ L 195.973649 301.005225 L 196.243446 300.99928 L 196.513243 300.995774 L 196.78304 300.994624 -" clip-path="url(#p1141eee0a5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9737bb1b89)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9737bb1b89)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21099,7 +21099,7 @@ L 225.983193 311.378824 L 225.983193 292.743529 L 202.537815 292.743529 z -" clip-path="url(#pd48ecf06da)" style="fill: #2d2dff; opacity: 0.5; stroke: #2d2dff; stroke-linejoin: miter"/> +" clip-path="url(#p288cd7245f)" style="fill: #2d2dff; opacity: 0.5; stroke: #2d2dff; stroke-linejoin: miter"/> @@ -21184,12 +21184,12 @@ L 224.108103 301.004492 L 224.3779 300.998958 L 224.647697 300.995695 L 224.917494 300.994624 -" clip-path="url(#pd48ecf06da)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p288cd7245f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p288cd7245f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21207,7 +21207,7 @@ L 254.117647 311.378824 L 254.117647 292.743529 L 230.672269 292.743529 z -" clip-path="url(#p267f409bc7)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> +" clip-path="url(#p793cfb0c94)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> @@ -21292,12 +21292,12 @@ L 252.242556 300.991764 L 252.512354 300.993368 L 252.782151 300.994314 L 253.051948 300.994624 -" clip-path="url(#p267f409bc7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p793cfb0c94)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p793cfb0c94)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21315,7 +21315,7 @@ L 282.252101 311.378824 L 282.252101 292.743529 L 258.806723 292.743529 z -" clip-path="url(#p905f8f9d64)" style="fill: #ddddff; opacity: 0.5; stroke: #ddddff; stroke-linejoin: miter"/> +" clip-path="url(#pa5bb6f732d)" style="fill: #ddddff; opacity: 0.5; stroke: #ddddff; stroke-linejoin: miter"/> @@ -21400,12 +21400,12 @@ L 280.37701 300.999115 L 280.646807 300.996597 L 280.916605 300.995112 L 281.186402 300.994624 -" clip-path="url(#p905f8f9d64)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa5bb6f732d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa5bb6f732d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21423,7 +21423,7 @@ L 310.386555 311.378824 L 310.386555 292.743529 L 286.941176 292.743529 z -" clip-path="url(#pcc401b23d6)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> +" clip-path="url(#p88f0bb51b6)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> @@ -21508,12 +21508,12 @@ L 308.511464 300.996323 L 308.781261 300.99537 L 309.051058 300.994809 L 309.320856 300.994624 -" clip-path="url(#pcc401b23d6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p88f0bb51b6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p88f0bb51b6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21531,7 +21531,7 @@ L 338.521008 311.378824 L 338.521008 292.743529 L 315.07563 292.743529 z -" clip-path="url(#p6a274e6637)" style="fill: #ffd1d1; opacity: 0.5; stroke: #ffd1d1; stroke-linejoin: miter"/> +" clip-path="url(#p8093704fe2)" style="fill: #ffd1d1; opacity: 0.5; stroke: #ffd1d1; stroke-linejoin: miter"/> @@ -21616,12 +21616,12 @@ L 336.645918 300.990047 L 336.915715 300.992614 L 337.185512 300.994128 L 337.455309 300.994624 -" clip-path="url(#p6a274e6637)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8093704fe2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8093704fe2)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21639,7 +21639,7 @@ L 366.655462 311.378824 L 366.655462 292.743529 L 343.210084 292.743529 z -" clip-path="url(#p6d13d72b0d)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#pffe5597492)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -21724,12 +21724,12 @@ L 364.780372 300.994484 L 365.050169 300.994563 L 365.319966 300.994609 L 365.589763 300.994624 -" clip-path="url(#p6d13d72b0d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pffe5597492)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pffe5597492)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21747,7 +21747,7 @@ L 394.789916 311.378824 L 394.789916 292.743529 L 371.344538 292.743529 z -" clip-path="url(#pd8da9fe289)" style="fill: #ff5959; opacity: 0.5; stroke: #ff5959; stroke-linejoin: miter"/> +" clip-path="url(#p2f4bd75036)" style="fill: #ff5959; opacity: 0.5; stroke: #ff5959; stroke-linejoin: miter"/> @@ -21832,12 +21832,12 @@ L 392.914825 300.993743 L 393.184623 300.994237 L 393.45442 300.994529 L 393.724217 300.994624 -" clip-path="url(#pd8da9fe289)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2f4bd75036)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2f4bd75036)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21855,7 +21855,7 @@ L 422.92437 311.378824 L 422.92437 292.743529 L 399.478992 292.743529 z -" clip-path="url(#pb326fe52a0)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#p41ab02049c)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -21940,12 +21940,12 @@ L 421.049279 300.99139 L 421.319076 300.993204 L 421.588874 300.994273 L 421.858671 300.994624 -" clip-path="url(#pb326fe52a0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p41ab02049c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p41ab02049c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21963,7 +21963,7 @@ L 451.058824 311.378824 L 451.058824 292.743529 L 427.613445 292.743529 z -" clip-path="url(#p18e4a0741e)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> +" clip-path="url(#pbdebf22f05)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> @@ -22048,12 +22048,12 @@ L 449.183733 300.990506 L 449.45353 300.992816 L 449.723327 300.994178 L 449.993125 300.994624 -" clip-path="url(#p18e4a0741e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbdebf22f05)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbdebf22f05)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22071,7 +22071,7 @@ L 479.193277 311.378824 L 479.193277 292.743529 L 455.747899 292.743529 z -" clip-path="url(#pcb50a10722)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> +" clip-path="url(#p515fc82d5c)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> @@ -22156,12 +22156,12 @@ L 477.318187 300.990817 L 477.587984 300.992952 L 477.857781 300.994211 L 478.127578 300.994624 -" clip-path="url(#pcb50a10722)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p515fc82d5c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p515fc82d5c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22179,7 +22179,7 @@ L 507.327731 311.378824 L 507.327731 292.743529 L 483.882353 292.743529 z -" clip-path="url(#p5f3b3d9601)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> +" clip-path="url(#p7525a41f45)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> @@ -22264,12 +22264,12 @@ L 505.45264 300.995656 L 505.722438 300.995078 L 505.992235 300.994736 L 506.262032 300.994624 -" clip-path="url(#p5f3b3d9601)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7525a41f45)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7525a41f45)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22287,7 +22287,7 @@ L 535.462185 311.378824 L 535.462185 292.743529 L 512.016807 292.743529 z -" clip-path="url(#p0638888184)" style="fill: #ffc5c5; opacity: 0.5; stroke: #ffc5c5; stroke-linejoin: miter"/> +" clip-path="url(#p7876017902)" style="fill: #ffc5c5; opacity: 0.5; stroke: #ffc5c5; stroke-linejoin: miter"/> @@ -22372,12 +22372,12 @@ L 533.587094 300.993413 L 533.856891 300.994092 L 534.126689 300.994493 L 534.396486 300.994624 -" clip-path="url(#p0638888184)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7876017902)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7876017902)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22395,7 +22395,7 @@ L 563.596639 311.378824 L 563.596639 292.743529 L 540.151261 292.743529 z -" clip-path="url(#p3a13aa791d)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> +" clip-path="url(#pcebaaea103)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> @@ -22480,12 +22480,12 @@ L 561.721548 300.995005 L 561.991345 300.994792 L 562.261142 300.994666 L 562.53094 300.994624 -" clip-path="url(#p3a13aa791d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcebaaea103)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcebaaea103)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22503,7 +22503,7 @@ L 591.731092 311.378824 L 591.731092 292.743529 L 568.285714 292.743529 z -" clip-path="url(#p2aeb4111ce)" style="fill: #00004c; opacity: 0.5; stroke: #00004c; stroke-linejoin: miter"/> +" clip-path="url(#p667bd811c7)" style="fill: #00004c; opacity: 0.5; stroke: #00004c; stroke-linejoin: miter"/> @@ -22588,12 +22588,12 @@ L 589.856002 301.024648 L 590.125799 301.007811 L 590.395596 300.997881 L 590.665393 300.994624 -" clip-path="url(#p2aeb4111ce)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p667bd811c7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p667bd811c7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22611,7 +22611,7 @@ L 619.865546 311.378824 L 619.865546 292.743529 L 596.420168 292.743529 z -" clip-path="url(#p8736998af9)" style="fill: #2525ff; opacity: 0.5; stroke: #2525ff; stroke-linejoin: miter"/> +" clip-path="url(#peec5f9eef7)" style="fill: #2525ff; opacity: 0.5; stroke: #2525ff; stroke-linejoin: miter"/> @@ -22696,12 +22696,12 @@ L 617.990456 301.007524 L 618.260253 301.00029 L 618.53005 300.996024 L 618.799847 300.994624 -" clip-path="url(#p8736998af9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#peec5f9eef7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#peec5f9eef7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22719,7 +22719,7 @@ L 113.445378 333.741176 L 113.445378 315.105882 L 90 315.105882 z -" clip-path="url(#p818416edc7)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p2e6782d8bd)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -22804,12 +22804,12 @@ L 111.570287 322.525789 L 111.840085 322.528704 L 112.109882 322.530424 L 112.379679 322.530988 -" clip-path="url(#p818416edc7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2e6782d8bd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2e6782d8bd)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22827,7 +22827,7 @@ L 141.579832 333.741176 L 141.579832 315.105882 L 118.134454 315.105882 z -" clip-path="url(#p5f1fe7b4e5)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> +" clip-path="url(#pcf5c17fc87)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> @@ -22912,12 +22912,12 @@ L 139.704741 322.531749 L 139.974538 322.531322 L 140.244336 322.531071 L 140.514133 322.530988 -" clip-path="url(#p5f1fe7b4e5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcf5c17fc87)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcf5c17fc87)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22935,7 +22935,7 @@ L 169.714286 333.741176 L 169.714286 315.105882 L 146.268908 315.105882 z -" clip-path="url(#p0d3344e6fb)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> +" clip-path="url(#p2b5a8e9a23)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> @@ -23020,12 +23020,12 @@ L 167.839195 322.529704 L 168.108992 322.530424 L 168.378789 322.530849 L 168.648587 322.530988 -" clip-path="url(#p0d3344e6fb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2b5a8e9a23)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2b5a8e9a23)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23043,7 +23043,7 @@ L 197.848739 333.741176 L 197.848739 315.105882 L 174.403361 315.105882 z -" clip-path="url(#pf838414fe5)" style="fill: #ff5959; opacity: 0.5; stroke: #ff5959; stroke-linejoin: miter"/> +" clip-path="url(#p0392a32810)" style="fill: #ff5959; opacity: 0.5; stroke: #ff5959; stroke-linejoin: miter"/> @@ -23128,12 +23128,12 @@ L 195.973649 322.526742 L 196.243446 322.529123 L 196.513243 322.530527 L 196.78304 322.530988 -" clip-path="url(#pf838414fe5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0392a32810)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0392a32810)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23151,7 +23151,7 @@ L 225.983193 333.741176 L 225.983193 315.105882 L 202.537815 315.105882 z -" clip-path="url(#p2d53ab164b)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> +" clip-path="url(#pe1664c6bc3)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> @@ -23236,12 +23236,12 @@ L 224.108103 322.535822 L 224.3779 322.533111 L 224.647697 322.531512 L 224.917494 322.530988 -" clip-path="url(#p2d53ab164b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe1664c6bc3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe1664c6bc3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23259,7 +23259,7 @@ L 254.117647 333.741176 L 254.117647 315.105882 L 230.672269 315.105882 z -" clip-path="url(#p10e2901bda)" style="fill: #2d2dff; opacity: 0.5; stroke: #2d2dff; stroke-linejoin: miter"/> +" clip-path="url(#p835600de6b)" style="fill: #2d2dff; opacity: 0.5; stroke: #2d2dff; stroke-linejoin: miter"/> @@ -23344,12 +23344,12 @@ L 252.242556 322.541348 L 252.512354 322.535538 L 252.782151 322.532112 L 253.051948 322.530988 -" clip-path="url(#p10e2901bda)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p835600de6b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p835600de6b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23367,7 +23367,7 @@ L 282.252101 333.741176 L 282.252101 315.105882 L 258.806723 315.105882 z -" clip-path="url(#p0cf1f47fd3)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> +" clip-path="url(#paad500e6ad)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> @@ -23452,12 +23452,12 @@ L 280.37701 322.538457 L 280.646807 322.534268 L 280.916605 322.531798 L 281.186402 322.530988 -" clip-path="url(#p0cf1f47fd3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paad500e6ad)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paad500e6ad)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23475,7 +23475,7 @@ L 310.386555 333.741176 L 310.386555 315.105882 L 286.941176 315.105882 z -" clip-path="url(#p2ab482a533)" style="fill: #0000fa; opacity: 0.5; stroke: #0000fa; stroke-linejoin: miter"/> +" clip-path="url(#p09e21916dc)" style="fill: #0000fa; opacity: 0.5; stroke: #0000fa; stroke-linejoin: miter"/> @@ -23560,12 +23560,12 @@ L 308.511464 322.54799 L 308.781261 322.538455 L 309.051058 322.532832 L 309.320856 322.530988 -" clip-path="url(#p2ab482a533)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p09e21916dc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p09e21916dc)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23583,7 +23583,7 @@ L 338.521008 333.741176 L 338.521008 315.105882 L 315.07563 315.105882 z -" clip-path="url(#pd6c75b88b2)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> +" clip-path="url(#p9d3d848f48)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> @@ -23668,12 +23668,12 @@ L 336.645918 322.539368 L 336.915715 322.534668 L 337.185512 322.531897 L 337.455309 322.530988 -" clip-path="url(#pd6c75b88b2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9d3d848f48)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9d3d848f48)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23691,7 +23691,7 @@ L 366.655462 333.741176 L 366.655462 315.105882 L 343.210084 315.105882 z -" clip-path="url(#pf39fc450f2)" style="fill: #ffb9b9; opacity: 0.5; stroke: #ffb9b9; stroke-linejoin: miter"/> +" clip-path="url(#p4f0ee939c7)" style="fill: #ffb9b9; opacity: 0.5; stroke: #ffb9b9; stroke-linejoin: miter"/> @@ -23776,12 +23776,12 @@ L 364.780372 322.529654 L 365.050169 322.530402 L 365.319966 322.530843 L 365.589763 322.530988 -" clip-path="url(#pf39fc450f2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4f0ee939c7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4f0ee939c7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23799,7 +23799,7 @@ L 394.789916 333.741176 L 394.789916 315.105882 L 371.344538 315.105882 z -" clip-path="url(#pab320155e9)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> +" clip-path="url(#p0efb77703c)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> @@ -23884,12 +23884,12 @@ L 392.914825 322.529935 L 393.184623 322.530526 L 393.45442 322.530874 L 393.724217 322.530988 -" clip-path="url(#pab320155e9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0efb77703c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0efb77703c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23907,7 +23907,7 @@ L 422.92437 333.741176 L 422.92437 315.105882 L 399.478992 315.105882 z -" clip-path="url(#p0104bb5c11)" style="fill: #ff9595; opacity: 0.5; stroke: #ff9595; stroke-linejoin: miter"/> +" clip-path="url(#p11b34b8692)" style="fill: #ff9595; opacity: 0.5; stroke: #ff9595; stroke-linejoin: miter"/> @@ -23992,12 +23992,12 @@ L 421.049279 322.527167 L 421.319076 322.52931 L 421.588874 322.530574 L 421.858671 322.530988 -" clip-path="url(#p0104bb5c11)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p11b34b8692)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p11b34b8692)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24015,7 +24015,7 @@ L 451.058824 333.741176 L 451.058824 315.105882 L 427.613445 315.105882 z -" clip-path="url(#pd72c6ff218)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#pe001d75801)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -24100,12 +24100,12 @@ L 449.183733 322.532624 L 449.45353 322.531707 L 449.723327 322.531166 L 449.993125 322.530988 -" clip-path="url(#pd72c6ff218)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe001d75801)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe001d75801)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24123,7 +24123,7 @@ L 479.193277 333.741176 L 479.193277 315.105882 L 455.747899 315.105882 z -" clip-path="url(#p2e9515d7a2)" style="fill: #ff6969; opacity: 0.5; stroke: #ff6969; stroke-linejoin: miter"/> +" clip-path="url(#p23071db74c)" style="fill: #ff6969; opacity: 0.5; stroke: #ff6969; stroke-linejoin: miter"/> @@ -24208,12 +24208,12 @@ L 477.318187 322.52435 L 477.587984 322.528073 L 477.857781 322.530268 L 478.127578 322.530988 -" clip-path="url(#p2e9515d7a2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p23071db74c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p23071db74c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24231,7 +24231,7 @@ L 507.327731 333.741176 L 507.327731 315.105882 L 483.882353 315.105882 z -" clip-path="url(#pf9b37ef074)" style="fill: #ff9595; opacity: 0.5; stroke: #ff9595; stroke-linejoin: miter"/> +" clip-path="url(#p2f3e8b1248)" style="fill: #ff9595; opacity: 0.5; stroke: #ff9595; stroke-linejoin: miter"/> @@ -24316,12 +24316,12 @@ L 505.45264 322.525609 L 505.722438 322.528626 L 505.992235 322.530405 L 506.262032 322.530988 -" clip-path="url(#pf9b37ef074)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2f3e8b1248)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2f3e8b1248)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24339,7 +24339,7 @@ L 535.462185 333.741176 L 535.462185 315.105882 L 512.016807 315.105882 z -" clip-path="url(#p35605e1517)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> +" clip-path="url(#p07896f5fa0)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> @@ -24424,12 +24424,12 @@ L 533.587094 322.528155 L 533.856891 322.529744 L 534.126689 322.530681 L 534.396486 322.530988 -" clip-path="url(#p35605e1517)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p07896f5fa0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p07896f5fa0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24447,7 +24447,7 @@ L 563.596639 333.741176 L 563.596639 315.105882 L 540.151261 315.105882 z -" clip-path="url(#p95a10a362d)" style="fill: #c9c9ff; opacity: 0.5; stroke: #c9c9ff; stroke-linejoin: miter"/> +" clip-path="url(#pc29995acad)" style="fill: #c9c9ff; opacity: 0.5; stroke: #c9c9ff; stroke-linejoin: miter"/> @@ -24532,12 +24532,12 @@ L 561.721548 322.531563 L 561.991345 322.531241 L 562.261142 322.53105 L 562.53094 322.530988 -" clip-path="url(#p95a10a362d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc29995acad)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc29995acad)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24555,7 +24555,7 @@ L 591.731092 333.741176 L 591.731092 315.105882 L 568.285714 315.105882 z -" clip-path="url(#pcbb3a3518a)" style="fill: #000055; opacity: 0.5; stroke: #000055; stroke-linejoin: miter"/> +" clip-path="url(#p6478a9d58a)" style="fill: #000055; opacity: 0.5; stroke: #000055; stroke-linejoin: miter"/> @@ -24640,12 +24640,12 @@ L 589.856002 322.561348 L 590.125799 322.544322 L 590.395596 322.534282 L 590.665393 322.530988 -" clip-path="url(#pcbb3a3518a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6478a9d58a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6478a9d58a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24663,7 +24663,7 @@ L 619.865546 333.741176 L 619.865546 315.105882 L 596.420168 315.105882 z -" clip-path="url(#p716ed173e9)" style="fill: #1919ff; opacity: 0.5; stroke: #1919ff; stroke-linejoin: miter"/> +" clip-path="url(#p3b80dec32f)" style="fill: #1919ff; opacity: 0.5; stroke: #1919ff; stroke-linejoin: miter"/> @@ -24748,12 +24748,12 @@ L 617.990456 322.545023 L 618.260253 322.537152 L 618.53005 322.532511 L 618.799847 322.530988 -" clip-path="url(#p716ed173e9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3b80dec32f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3b80dec32f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24771,7 +24771,7 @@ L 113.445378 356.103529 L 113.445378 337.468235 L 90 337.468235 z -" clip-path="url(#p50b0a2a44e)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> +" clip-path="url(#p82c01defcf)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> @@ -24856,12 +24856,12 @@ L 111.570287 347.58233 L 111.840085 347.577814 L 112.109882 347.575151 L 112.379679 347.574277 -" clip-path="url(#p50b0a2a44e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p82c01defcf)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p82c01defcf)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24879,7 +24879,7 @@ L 141.579832 356.103529 L 141.579832 337.468235 L 118.134454 337.468235 z -" clip-path="url(#p805609aecd)" style="fill: #6969ff; opacity: 0.5; stroke: #6969ff; stroke-linejoin: miter"/> +" clip-path="url(#pb53ab6bf85)" style="fill: #6969ff; opacity: 0.5; stroke: #6969ff; stroke-linejoin: miter"/> @@ -24964,12 +24964,12 @@ L 139.704741 347.586485 L 139.974538 347.579639 L 140.244336 347.575602 L 140.514133 347.574277 -" clip-path="url(#p805609aecd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb53ab6bf85)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb53ab6bf85)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24987,7 +24987,7 @@ L 169.714286 356.103529 L 169.714286 337.468235 L 146.268908 337.468235 z -" clip-path="url(#p5307852d9c)" style="fill: #5151ff; opacity: 0.5; stroke: #5151ff; stroke-linejoin: miter"/> +" clip-path="url(#pffdbd8662c)" style="fill: #5151ff; opacity: 0.5; stroke: #5151ff; stroke-linejoin: miter"/> @@ -25072,12 +25072,12 @@ L 167.839195 347.593386 L 168.108992 347.58267 L 168.378789 347.57635 L 168.648587 347.574277 -" clip-path="url(#p5307852d9c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pffdbd8662c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pffdbd8662c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25095,7 +25095,7 @@ L 197.848739 356.103529 L 197.848739 337.468235 L 174.403361 337.468235 z -" clip-path="url(#p7124eec22d)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#p8f3733f5e7)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -25180,12 +25180,12 @@ L 195.973649 347.577055 L 196.243446 347.575497 L 196.513243 347.574579 L 196.78304 347.574277 -" clip-path="url(#p7124eec22d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8f3733f5e7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8f3733f5e7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25203,7 +25203,7 @@ L 225.983193 356.103529 L 225.983193 337.468235 L 202.537815 337.468235 z -" clip-path="url(#pe3a24c1499)" style="fill: #0000de; opacity: 0.5; stroke: #0000de; stroke-linejoin: miter"/> +" clip-path="url(#p84a7492904)" style="fill: #0000de; opacity: 0.5; stroke: #0000de; stroke-linejoin: miter"/> @@ -25288,12 +25288,12 @@ L 224.108103 347.595181 L 224.3779 347.583458 L 224.647697 347.576545 L 224.917494 347.574277 -" clip-path="url(#pe3a24c1499)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p84a7492904)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p84a7492904)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25311,7 +25311,7 @@ L 254.117647 356.103529 L 254.117647 337.468235 L 230.672269 337.468235 z -" clip-path="url(#p210bf0a2de)" style="fill: #0505ff; opacity: 0.5; stroke: #0505ff; stroke-linejoin: miter"/> +" clip-path="url(#p526622246b)" style="fill: #0505ff; opacity: 0.5; stroke: #0505ff; stroke-linejoin: miter"/> @@ -25396,12 +25396,12 @@ L 252.242556 347.594712 L 252.512354 347.583252 L 252.782151 347.576494 L 253.051948 347.574277 -" clip-path="url(#p210bf0a2de)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p526622246b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p526622246b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25419,7 +25419,7 @@ L 282.252101 356.103529 L 282.252101 337.468235 L 258.806723 337.468235 z -" clip-path="url(#pd1375159d0)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> +" clip-path="url(#p5dca5231d7)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> @@ -25504,12 +25504,12 @@ L 280.37701 347.581915 L 280.646807 347.577632 L 280.916605 347.575106 L 281.186402 347.574277 -" clip-path="url(#pd1375159d0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5dca5231d7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5dca5231d7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25527,7 +25527,7 @@ L 310.386555 356.103529 L 310.386555 337.468235 L 286.941176 337.468235 z -" clip-path="url(#p9192637b45)" style="fill: #4d4dff; opacity: 0.5; stroke: #4d4dff; stroke-linejoin: miter"/> +" clip-path="url(#p4c9f592c1e)" style="fill: #4d4dff; opacity: 0.5; stroke: #4d4dff; stroke-linejoin: miter"/> @@ -25612,12 +25612,12 @@ L 308.511464 347.591438 L 308.781261 347.581815 L 309.051058 347.576139 L 309.320856 347.574277 -" clip-path="url(#p9192637b45)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4c9f592c1e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4c9f592c1e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25635,7 +25635,7 @@ L 338.521008 356.103529 L 338.521008 337.468235 L 315.07563 337.468235 z -" clip-path="url(#pc0bd8d9a44)" style="fill: #1d1dff; opacity: 0.5; stroke: #1d1dff; stroke-linejoin: miter"/> +" clip-path="url(#p7ef0dc4652)" style="fill: #1d1dff; opacity: 0.5; stroke: #1d1dff; stroke-linejoin: miter"/> @@ -25720,12 +25720,12 @@ L 336.645918 347.588832 L 336.915715 347.58067 L 337.185512 347.575856 L 337.455309 347.574277 -" clip-path="url(#pc0bd8d9a44)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ef0dc4652)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ef0dc4652)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25743,7 +25743,7 @@ L 366.655462 356.103529 L 366.655462 337.468235 L 343.210084 337.468235 z -" clip-path="url(#p4c6675d46e)" style="fill: #4545ff; opacity: 0.5; stroke: #4545ff; stroke-linejoin: miter"/> +" clip-path="url(#pa87599f5d5)" style="fill: #4545ff; opacity: 0.5; stroke: #4545ff; stroke-linejoin: miter"/> @@ -25828,12 +25828,12 @@ L 364.780372 347.583411 L 365.050169 347.578289 L 365.319966 347.575268 L 365.589763 347.574277 -" clip-path="url(#p4c6675d46e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa87599f5d5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa87599f5d5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25851,7 +25851,7 @@ L 394.789916 356.103529 L 394.789916 337.468235 L 371.344538 337.468235 z -" clip-path="url(#pd54b96efe5)" style="fill: #ffd5d5; opacity: 0.5; stroke: #ffd5d5; stroke-linejoin: miter"/> +" clip-path="url(#pc6f529eb9e)" style="fill: #ffd5d5; opacity: 0.5; stroke: #ffd5d5; stroke-linejoin: miter"/> @@ -25936,12 +25936,12 @@ L 392.914825 347.572295 L 393.184623 347.573407 L 393.45442 347.574062 L 393.724217 347.574277 -" clip-path="url(#pd54b96efe5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc6f529eb9e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc6f529eb9e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25959,7 +25959,7 @@ L 422.92437 356.103529 L 422.92437 337.468235 L 399.478992 337.468235 z -" clip-path="url(#pd71d464646)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#pa41621b1e2)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -26044,12 +26044,12 @@ L 421.049279 347.575632 L 421.319076 347.574872 L 421.588874 347.574424 L 421.858671 347.574277 -" clip-path="url(#pd71d464646)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa41621b1e2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa41621b1e2)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26067,7 +26067,7 @@ L 451.058824 356.103529 L 451.058824 337.468235 L 427.613445 337.468235 z -" clip-path="url(#p573f45905d)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#pf9c0cc3d3b)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -26152,12 +26152,12 @@ L 449.183733 347.570467 L 449.45353 347.572604 L 449.723327 347.573864 L 449.993125 347.574277 -" clip-path="url(#p573f45905d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf9c0cc3d3b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf9c0cc3d3b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26175,7 +26175,7 @@ L 479.193277 356.103529 L 479.193277 337.468235 L 455.747899 337.468235 z -" clip-path="url(#p857f4b52a0)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> +" clip-path="url(#p28d38c7d08)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> @@ -26260,12 +26260,12 @@ L 477.318187 347.574144 L 477.587984 347.574219 L 477.857781 347.574263 L 478.127578 347.574277 -" clip-path="url(#p857f4b52a0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p28d38c7d08)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p28d38c7d08)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26283,7 +26283,7 @@ L 507.327731 356.103529 L 507.327731 337.468235 L 483.882353 337.468235 z -" clip-path="url(#p62fc16713e)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> +" clip-path="url(#p1c21bf564d)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> @@ -26368,12 +26368,12 @@ L 505.45264 347.572207 L 505.722438 347.573368 L 505.992235 347.574053 L 506.262032 347.574277 -" clip-path="url(#p62fc16713e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1c21bf564d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1c21bf564d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26391,7 +26391,7 @@ L 535.462185 356.103529 L 535.462185 337.468235 L 512.016807 337.468235 z -" clip-path="url(#p69ea16b852)" style="fill: #ffeded; opacity: 0.5; stroke: #ffeded; stroke-linejoin: miter"/> +" clip-path="url(#p318b50fedd)" style="fill: #ffeded; opacity: 0.5; stroke: #ffeded; stroke-linejoin: miter"/> @@ -26476,12 +26476,12 @@ L 533.587094 347.578742 L 533.856891 347.576238 L 534.126689 347.574762 L 534.396486 347.574277 -" clip-path="url(#p69ea16b852)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p318b50fedd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p318b50fedd)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26499,7 +26499,7 @@ L 563.596639 356.103529 L 563.596639 337.468235 L 540.151261 337.468235 z -" clip-path="url(#p21059a8913)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> +" clip-path="url(#pfd8182c6a2)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> @@ -26584,12 +26584,12 @@ L 561.721548 347.575337 L 561.991345 347.574743 L 562.261142 347.574392 L 562.53094 347.574277 -" clip-path="url(#p21059a8913)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfd8182c6a2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfd8182c6a2)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26607,7 +26607,7 @@ L 591.731092 356.103529 L 591.731092 337.468235 L 568.285714 337.468235 z -" clip-path="url(#p2d2ffb39fe)" style="fill: #ff8181; opacity: 0.5; stroke: #ff8181; stroke-linejoin: miter"/> +" clip-path="url(#p2d3a5a7ec4)" style="fill: #ff8181; opacity: 0.5; stroke: #ff8181; stroke-linejoin: miter"/> @@ -26692,12 +26692,12 @@ L 589.856002 347.567215 L 590.125799 347.571176 L 590.395596 347.573511 L 590.665393 347.574277 -" clip-path="url(#p2d2ffb39fe)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d3a5a7ec4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d3a5a7ec4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26715,7 +26715,7 @@ L 619.865546 356.103529 L 619.865546 337.468235 L 596.420168 337.468235 z -" clip-path="url(#pc6d67363af)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> +" clip-path="url(#pd8a8a03cc1)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> @@ -26800,12 +26800,12 @@ L 617.990456 347.570843 L 618.260253 347.572769 L 618.53005 347.573905 L 618.799847 347.574277 -" clip-path="url(#pc6d67363af)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd8a8a03cc1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd8a8a03cc1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26823,7 +26823,7 @@ L 113.445378 378.465882 L 113.445378 359.830588 L 90 359.830588 z -" clip-path="url(#pf4994b72bd)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> +" clip-path="url(#p9e4a180832)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> @@ -26908,12 +26908,12 @@ L 111.570287 369.250612 L 111.840085 369.251272 L 112.109882 369.251661 L 112.379679 369.251788 -" clip-path="url(#pf4994b72bd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9e4a180832)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9e4a180832)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26931,7 +26931,7 @@ L 141.579832 378.465882 L 141.579832 359.830588 L 118.134454 359.830588 z -" clip-path="url(#p749f63e8d3)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#p003c3fa978)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -27016,12 +27016,12 @@ L 139.704741 369.249925 L 139.974538 369.25097 L 140.244336 369.251586 L 140.514133 369.251788 -" clip-path="url(#p749f63e8d3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p003c3fa978)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p003c3fa978)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27039,7 +27039,7 @@ L 169.714286 378.465882 L 169.714286 359.830588 L 146.268908 359.830588 z -" clip-path="url(#p0fb23e3e31)" style="fill: #ff5959; opacity: 0.5; stroke: #ff5959; stroke-linejoin: miter"/> +" clip-path="url(#p90738b0cc9)" style="fill: #ff5959; opacity: 0.5; stroke: #ff5959; stroke-linejoin: miter"/> @@ -27124,12 +27124,12 @@ L 167.839195 369.252233 L 168.108992 369.251984 L 168.378789 369.251837 L 168.648587 369.251788 -" clip-path="url(#p0fb23e3e31)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p90738b0cc9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p90738b0cc9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27147,7 +27147,7 @@ L 197.848739 378.465882 L 197.848739 359.830588 L 174.403361 359.830588 z -" clip-path="url(#p89d14f7956)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> +" clip-path="url(#p36431d8e76)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> @@ -27232,12 +27232,12 @@ L 195.973649 369.249071 L 196.243446 369.250595 L 196.513243 369.251494 L 196.78304 369.251788 -" clip-path="url(#p89d14f7956)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p36431d8e76)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p36431d8e76)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27255,7 +27255,7 @@ L 225.983193 378.465882 L 225.983193 359.830588 L 202.537815 359.830588 z -" clip-path="url(#p3aa0912ed9)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#p6297a8e0a5)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -27340,12 +27340,12 @@ L 224.108103 369.254011 L 224.3779 369.252764 L 224.647697 369.252029 L 224.917494 369.251788 -" clip-path="url(#p3aa0912ed9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6297a8e0a5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6297a8e0a5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27363,7 +27363,7 @@ L 254.117647 378.465882 L 254.117647 359.830588 L 230.672269 359.830588 z -" clip-path="url(#pccc3defb6d)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> +" clip-path="url(#p00d8e078d3)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> @@ -27448,12 +27448,12 @@ L 252.242556 369.256674 L 252.512354 369.253934 L 252.782151 369.252318 L 253.051948 369.251788 -" clip-path="url(#pccc3defb6d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p00d8e078d3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p00d8e078d3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27471,7 +27471,7 @@ L 282.252101 378.465882 L 282.252101 359.830588 L 258.806723 359.830588 z -" clip-path="url(#pd8637aeb91)" style="fill: #7d7dff; opacity: 0.5; stroke: #7d7dff; stroke-linejoin: miter"/> +" clip-path="url(#p5ab17500cf)" style="fill: #7d7dff; opacity: 0.5; stroke: #7d7dff; stroke-linejoin: miter"/> @@ -27556,12 +27556,12 @@ L 280.37701 369.258876 L 280.646807 369.254901 L 280.916605 369.252557 L 281.186402 369.251788 -" clip-path="url(#pd8637aeb91)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5ab17500cf)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5ab17500cf)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27579,7 +27579,7 @@ L 310.386555 378.465882 L 310.386555 359.830588 L 286.941176 359.830588 z -" clip-path="url(#p5b29a7b325)" style="fill: #0000ae; opacity: 0.5; stroke: #0000ae; stroke-linejoin: miter"/> +" clip-path="url(#p5a3b170067)" style="fill: #0000ae; opacity: 0.5; stroke: #0000ae; stroke-linejoin: miter"/> @@ -27664,12 +27664,12 @@ L 308.511464 369.27243 L 308.781261 369.260854 L 309.051058 369.254028 L 309.320856 369.251788 -" clip-path="url(#p5b29a7b325)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5a3b170067)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5a3b170067)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27687,7 +27687,7 @@ L 338.521008 378.465882 L 338.521008 359.830588 L 315.07563 359.830588 z -" clip-path="url(#p4ff648f573)" style="fill: #4141ff; opacity: 0.5; stroke: #4141ff; stroke-linejoin: miter"/> +" clip-path="url(#p1b8dc0cb84)" style="fill: #4141ff; opacity: 0.5; stroke: #4141ff; stroke-linejoin: miter"/> @@ -27772,12 +27772,12 @@ L 336.645918 369.26069 L 336.915715 369.255698 L 337.185512 369.252754 L 337.455309 369.251788 -" clip-path="url(#p4ff648f573)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1b8dc0cb84)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1b8dc0cb84)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27795,7 +27795,7 @@ L 366.655462 378.465882 L 366.655462 359.830588 L 343.210084 359.830588 z -" clip-path="url(#pe1b8eafd94)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> +" clip-path="url(#pd6d748ac1b)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> @@ -27880,12 +27880,12 @@ L 364.780372 369.241203 L 365.050169 369.247139 L 365.319966 369.25064 L 365.589763 369.251788 -" clip-path="url(#pe1b8eafd94)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd6d748ac1b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd6d748ac1b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27903,7 +27903,7 @@ L 394.789916 378.465882 L 394.789916 359.830588 L 371.344538 359.830588 z -" clip-path="url(#p45f1ab2e11)" style="fill: #ff7575; opacity: 0.5; stroke: #ff7575; stroke-linejoin: miter"/> +" clip-path="url(#p03ca37afdf)" style="fill: #ff7575; opacity: 0.5; stroke: #ff7575; stroke-linejoin: miter"/> @@ -27988,12 +27988,12 @@ L 392.914825 369.248174 L 393.184623 369.250201 L 393.45442 369.251396 L 393.724217 369.251788 -" clip-path="url(#p45f1ab2e11)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p03ca37afdf)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p03ca37afdf)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28011,7 +28011,7 @@ L 422.92437 378.465882 L 422.92437 359.830588 L 399.478992 359.830588 z -" clip-path="url(#pce1251983f)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> +" clip-path="url(#p135c201e2d)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> @@ -28096,12 +28096,12 @@ L 421.049279 369.254431 L 421.319076 369.252949 L 421.588874 369.252075 L 421.858671 369.251788 -" clip-path="url(#pce1251983f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p135c201e2d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p135c201e2d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28119,7 +28119,7 @@ L 451.058824 378.465882 L 451.058824 359.830588 L 427.613445 359.830588 z -" clip-path="url(#p8da23a69bd)" style="fill: #ff6161; opacity: 0.5; stroke: #ff6161; stroke-linejoin: miter"/> +" clip-path="url(#p88c6dce251)" style="fill: #ff6161; opacity: 0.5; stroke: #ff6161; stroke-linejoin: miter"/> @@ -28204,12 +28204,12 @@ L 449.183733 369.253163 L 449.45353 369.252392 L 449.723327 369.251937 L 449.993125 369.251788 -" clip-path="url(#p8da23a69bd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p88c6dce251)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p88c6dce251)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28227,7 +28227,7 @@ L 479.193277 378.465882 L 479.193277 359.830588 L 455.747899 359.830588 z -" clip-path="url(#pb8e304de3d)" style="fill: #ff5d5d; opacity: 0.5; stroke: #ff5d5d; stroke-linejoin: miter"/> +" clip-path="url(#p639763f5c3)" style="fill: #ff5d5d; opacity: 0.5; stroke: #ff5d5d; stroke-linejoin: miter"/> @@ -28312,12 +28312,12 @@ L 477.318187 369.25178 L 477.587984 369.251785 L 477.857781 369.251787 L 478.127578 369.251788 -" clip-path="url(#pb8e304de3d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p639763f5c3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p639763f5c3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28335,7 +28335,7 @@ L 507.327731 378.465882 L 507.327731 359.830588 L 483.882353 359.830588 z -" clip-path="url(#pbd6030649a)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p41a991b70e)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -28420,12 +28420,12 @@ L 505.45264 369.24685 L 505.722438 369.249619 L 505.992235 369.251253 L 506.262032 369.251788 -" clip-path="url(#pbd6030649a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p41a991b70e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p41a991b70e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28443,7 +28443,7 @@ L 535.462185 378.465882 L 535.462185 359.830588 L 512.016807 359.830588 z -" clip-path="url(#p409c214a63)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> +" clip-path="url(#pb0485dc74f)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> @@ -28528,12 +28528,12 @@ L 533.587094 369.250883 L 533.856891 369.251391 L 534.126689 369.25169 L 534.396486 369.251788 -" clip-path="url(#p409c214a63)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb0485dc74f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb0485dc74f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28551,7 +28551,7 @@ L 563.596639 378.465882 L 563.596639 359.830588 L 540.151261 359.830588 z -" clip-path="url(#p93aa5c7dfd)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> +" clip-path="url(#p7155266994)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> @@ -28636,12 +28636,12 @@ L 561.721548 369.255898 L 561.991345 369.253593 L 562.261142 369.252234 L 562.53094 369.251788 -" clip-path="url(#p93aa5c7dfd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7155266994)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7155266994)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28659,7 +28659,7 @@ L 591.731092 378.465882 L 591.731092 359.830588 L 568.285714 359.830588 z -" clip-path="url(#p98c2c4c431)" style="fill: #e1e1ff; opacity: 0.5; stroke: #e1e1ff; stroke-linejoin: miter"/> +" clip-path="url(#pca900533b1)" style="fill: #e1e1ff; opacity: 0.5; stroke: #e1e1ff; stroke-linejoin: miter"/> @@ -28744,12 +28744,12 @@ L 589.856002 369.254953 L 590.125799 369.253178 L 590.395596 369.252132 L 590.665393 369.251788 -" clip-path="url(#p98c2c4c431)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pca900533b1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pca900533b1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28767,7 +28767,7 @@ L 619.865546 378.465882 L 619.865546 359.830588 L 596.420168 359.830588 z -" clip-path="url(#p71594f7054)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#pde7ed88ea4)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -28852,12 +28852,12 @@ L 617.990456 369.25581 L 618.260253 369.253554 L 618.53005 369.252225 L 618.799847 369.251788 -" clip-path="url(#p71594f7054)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pde7ed88ea4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pde7ed88ea4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28875,7 +28875,7 @@ L 113.445378 400.828235 L 113.445378 382.192941 L 90 382.192941 z -" clip-path="url(#p040acb652d)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> +" clip-path="url(#pa1cc92e239)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> @@ -28960,12 +28960,12 @@ L 111.570287 392.679561 L 111.840085 392.6747 L 112.109882 392.671833 L 112.379679 392.670893 -" clip-path="url(#p040acb652d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa1cc92e239)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa1cc92e239)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28983,7 +28983,7 @@ L 141.579832 400.828235 L 141.579832 382.192941 L 118.134454 382.192941 z -" clip-path="url(#p5c21a2aa63)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> +" clip-path="url(#p51eae4916d)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> @@ -29068,12 +29068,12 @@ L 139.704741 392.683622 L 139.974538 392.676484 L 140.244336 392.672274 L 140.514133 392.670893 -" clip-path="url(#p5c21a2aa63)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p51eae4916d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p51eae4916d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29091,7 +29091,7 @@ L 169.714286 400.828235 L 169.714286 382.192941 L 146.268908 382.192941 z -" clip-path="url(#p52c6d5b952)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> +" clip-path="url(#pd23268f27e)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> @@ -29176,12 +29176,12 @@ L 167.839195 392.690581 L 168.108992 392.67954 L 168.378789 392.673029 L 168.648587 392.670893 -" clip-path="url(#p52c6d5b952)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd23268f27e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd23268f27e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29199,7 +29199,7 @@ L 197.848739 400.828235 L 197.848739 382.192941 L 174.403361 382.192941 z -" clip-path="url(#pfc9bd6801c)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> +" clip-path="url(#p246adfd2f1)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> @@ -29284,12 +29284,12 @@ L 195.973649 392.681864 L 196.243446 392.675711 L 196.513243 392.672083 L 196.78304 392.670893 -" clip-path="url(#pfc9bd6801c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p246adfd2f1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p246adfd2f1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29307,7 +29307,7 @@ L 225.983193 400.828235 L 225.983193 382.192941 L 202.537815 382.192941 z -" clip-path="url(#p01e6375193)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> +" clip-path="url(#p6b69215851)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> @@ -29392,12 +29392,12 @@ L 224.108103 392.685461 L 224.3779 392.677291 L 224.647697 392.672473 L 224.917494 392.670893 -" clip-path="url(#p01e6375193)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6b69215851)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6b69215851)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29415,7 +29415,7 @@ L 254.117647 400.828235 L 254.117647 382.192941 L 230.672269 382.192941 z -" clip-path="url(#pd2a3e37e62)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> +" clip-path="url(#p5ca6990613)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> @@ -29500,12 +29500,12 @@ L 252.242556 392.694649 L 252.512354 392.681327 L 252.782151 392.67347 L 253.051948 392.670893 -" clip-path="url(#pd2a3e37e62)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5ca6990613)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5ca6990613)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29523,7 +29523,7 @@ L 282.252101 400.828235 L 282.252101 382.192941 L 258.806723 382.192941 z -" clip-path="url(#p0bb47c3fe0)" style="fill: #e1e1ff; opacity: 0.5; stroke: #e1e1ff; stroke-linejoin: miter"/> +" clip-path="url(#pcfb0cdc4ab)" style="fill: #e1e1ff; opacity: 0.5; stroke: #e1e1ff; stroke-linejoin: miter"/> @@ -29608,12 +29608,12 @@ L 280.37701 392.674501 L 280.646807 392.672478 L 280.916605 392.671284 L 281.186402 392.670893 -" clip-path="url(#p0bb47c3fe0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcfb0cdc4ab)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcfb0cdc4ab)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29631,7 +29631,7 @@ L 310.386555 400.828235 L 310.386555 382.192941 L 286.941176 382.192941 z -" clip-path="url(#p90fa1296bb)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> +" clip-path="url(#pe6179c6d71)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> @@ -29716,12 +29716,12 @@ L 308.511464 392.683464 L 308.781261 392.676414 L 309.051058 392.672256 L 309.320856 392.670893 -" clip-path="url(#p90fa1296bb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe6179c6d71)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe6179c6d71)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29739,7 +29739,7 @@ L 338.521008 400.828235 L 338.521008 382.192941 L 315.07563 382.192941 z -" clip-path="url(#pf282b057c9)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> +" clip-path="url(#pd448add62a)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> @@ -29824,12 +29824,12 @@ L 336.645918 392.685797 L 336.915715 392.677439 L 337.185512 392.67251 L 337.455309 392.670893 -" clip-path="url(#pf282b057c9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd448add62a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd448add62a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29847,7 +29847,7 @@ L 366.655462 400.828235 L 366.655462 382.192941 L 343.210084 382.192941 z -" clip-path="url(#pdce55bcf4b)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p446f39a24f)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -29932,12 +29932,12 @@ L 364.780372 392.680705 L 365.050169 392.675202 L 365.319966 392.671957 L 365.589763 392.670893 -" clip-path="url(#pdce55bcf4b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p446f39a24f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p446f39a24f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29955,7 +29955,7 @@ L 394.789916 400.828235 L 394.789916 382.192941 L 371.344538 382.192941 z -" clip-path="url(#pb68d034a43)" style="fill: #ffd1d1; opacity: 0.5; stroke: #ffd1d1; stroke-linejoin: miter"/> +" clip-path="url(#peaee05f51e)" style="fill: #ffd1d1; opacity: 0.5; stroke: #ffd1d1; stroke-linejoin: miter"/> @@ -30040,12 +30040,12 @@ L 392.914825 392.670642 L 393.184623 392.670783 L 393.45442 392.670866 L 393.724217 392.670893 -" clip-path="url(#pb68d034a43)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#peaee05f51e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#peaee05f51e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30063,7 +30063,7 @@ L 422.92437 400.828235 L 422.92437 382.192941 L 399.478992 382.192941 z -" clip-path="url(#pb3c2ae434a)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> +" clip-path="url(#p3e39b45530)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> @@ -30148,12 +30148,12 @@ L 421.049279 392.67871 L 421.319076 392.674326 L 421.588874 392.671741 L 421.858671 392.670893 -" clip-path="url(#pb3c2ae434a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3e39b45530)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3e39b45530)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30171,7 +30171,7 @@ L 451.058824 400.828235 L 451.058824 382.192941 L 427.613445 382.192941 z -" clip-path="url(#p8a22ca0d23)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> +" clip-path="url(#p5146197f30)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> @@ -30256,12 +30256,12 @@ L 449.183733 392.658006 L 449.45353 392.665233 L 449.723327 392.669495 L 449.993125 392.670893 -" clip-path="url(#p8a22ca0d23)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5146197f30)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5146197f30)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30279,7 +30279,7 @@ L 479.193277 400.828235 L 479.193277 382.192941 L 455.747899 382.192941 z -" clip-path="url(#pddae8cdf9c)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> +" clip-path="url(#p92ccf12f44)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> @@ -30364,12 +30364,12 @@ L 477.318187 392.694224 L 477.587984 392.68114 L 477.857781 392.673424 L 478.127578 392.670893 -" clip-path="url(#pddae8cdf9c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p92ccf12f44)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p92ccf12f44)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30387,7 +30387,7 @@ L 507.327731 400.828235 L 507.327731 382.192941 L 483.882353 382.192941 z -" clip-path="url(#p65088a56b5)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#pafa5d056b5)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -30472,12 +30472,12 @@ L 505.45264 392.643459 L 505.722438 392.658844 L 505.992235 392.667917 L 506.262032 392.670893 -" clip-path="url(#p65088a56b5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pafa5d056b5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pafa5d056b5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30495,7 +30495,7 @@ L 535.462185 400.828235 L 535.462185 382.192941 L 512.016807 382.192941 z -" clip-path="url(#pd15457ddca)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> +" clip-path="url(#p5ce99dbdcf)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> @@ -30580,12 +30580,12 @@ L 533.587094 392.679005 L 533.856891 392.674455 L 534.126689 392.671773 L 534.396486 392.670893 -" clip-path="url(#pd15457ddca)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5ce99dbdcf)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5ce99dbdcf)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30603,7 +30603,7 @@ L 563.596639 400.828235 L 563.596639 382.192941 L 540.151261 382.192941 z -" clip-path="url(#pb99178bb96)" style="fill: #ffc9c9; opacity: 0.5; stroke: #ffc9c9; stroke-linejoin: miter"/> +" clip-path="url(#p2e6ebf0bf7)" style="fill: #ffc9c9; opacity: 0.5; stroke: #ffc9c9; stroke-linejoin: miter"/> @@ -30688,12 +30688,12 @@ L 561.721548 392.6683 L 561.991345 392.669754 L 562.261142 392.670612 L 562.53094 392.670893 -" clip-path="url(#pb99178bb96)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2e6ebf0bf7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2e6ebf0bf7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30711,7 +30711,7 @@ L 591.731092 400.828235 L 591.731092 382.192941 L 568.285714 382.192941 z -" clip-path="url(#pba7b5a1d30)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#p3955840a10)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -30796,12 +30796,12 @@ L 589.856002 392.672609 L 590.125799 392.671647 L 590.395596 392.671079 L 590.665393 392.670893 -" clip-path="url(#pba7b5a1d30)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3955840a10)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3955840a10)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30819,7 +30819,7 @@ L 619.865546 400.828235 L 619.865546 382.192941 L 596.420168 382.192941 z -" clip-path="url(#pc6616ac3f9)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> +" clip-path="url(#pc7120b9a03)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> @@ -30904,12 +30904,12 @@ L 617.990456 392.667545 L 618.260253 392.669422 L 618.53005 392.67053 L 618.799847 392.670893 -" clip-path="url(#pc6616ac3f9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc7120b9a03)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc7120b9a03)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30927,7 +30927,7 @@ L 113.445378 423.190588 L 113.445378 404.555294 L 90 404.555294 z -" clip-path="url(#pe480333023)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> +" clip-path="url(#pcab0cd8681)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> @@ -31012,12 +31012,12 @@ L 111.570287 415.476795 L 111.840085 415.46583 L 112.109882 415.459363 L 112.379679 415.457242 -" clip-path="url(#pe480333023)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcab0cd8681)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcab0cd8681)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31035,7 +31035,7 @@ L 141.579832 423.190588 L 141.579832 404.555294 L 118.134454 404.555294 z -" clip-path="url(#p44f4c595c6)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#pc2e7d82265)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -31120,12 +31120,12 @@ L 139.704741 415.45785 L 139.974538 415.457509 L 140.244336 415.457308 L 140.514133 415.457242 -" clip-path="url(#p44f4c595c6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc2e7d82265)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc2e7d82265)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31143,7 +31143,7 @@ L 169.714286 423.190588 L 169.714286 404.555294 L 146.268908 404.555294 z -" clip-path="url(#pb41bfb7f52)" style="fill: #2d2dff; opacity: 0.5; stroke: #2d2dff; stroke-linejoin: miter"/> +" clip-path="url(#p339dda21e6)" style="fill: #2d2dff; opacity: 0.5; stroke: #2d2dff; stroke-linejoin: miter"/> @@ -31228,12 +31228,12 @@ L 167.839195 415.480716 L 168.108992 415.467552 L 168.378789 415.459789 L 168.648587 415.457242 -" clip-path="url(#pb41bfb7f52)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p339dda21e6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p339dda21e6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31251,7 +31251,7 @@ L 197.848739 423.190588 L 197.848739 404.555294 L 174.403361 404.555294 z -" clip-path="url(#p3afbe78a72)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> +" clip-path="url(#pe6f72e73fe)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> @@ -31336,12 +31336,12 @@ L 195.973649 415.468738 L 196.243446 415.462291 L 196.513243 415.458489 L 196.78304 415.457242 -" clip-path="url(#p3afbe78a72)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe6f72e73fe)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe6f72e73fe)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31359,7 +31359,7 @@ L 225.983193 423.190588 L 225.983193 404.555294 L 202.537815 404.555294 z -" clip-path="url(#p3893e18072)" style="fill: #4949ff; opacity: 0.5; stroke: #4949ff; stroke-linejoin: miter"/> +" clip-path="url(#p65d2056300)" style="fill: #4949ff; opacity: 0.5; stroke: #4949ff; stroke-linejoin: miter"/> @@ -31444,12 +31444,12 @@ L 224.108103 415.470715 L 224.3779 415.463159 L 224.647697 415.458704 L 224.917494 415.457242 -" clip-path="url(#p3893e18072)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p65d2056300)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p65d2056300)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31467,7 +31467,7 @@ L 254.117647 423.190588 L 254.117647 404.555294 L 230.672269 404.555294 z -" clip-path="url(#pf0ab4a13c0)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> +" clip-path="url(#p57b9bf43b9)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> @@ -31552,12 +31552,12 @@ L 252.242556 415.460686 L 252.512354 415.458755 L 252.782151 415.457616 L 253.051948 415.457242 -" clip-path="url(#pf0ab4a13c0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p57b9bf43b9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p57b9bf43b9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31575,7 +31575,7 @@ L 282.252101 423.190588 L 282.252101 404.555294 L 258.806723 404.555294 z -" clip-path="url(#p1263779708)" style="fill: #ffc1c1; opacity: 0.5; stroke: #ffc1c1; stroke-linejoin: miter"/> +" clip-path="url(#pa8dcf6bf44)" style="fill: #ffc1c1; opacity: 0.5; stroke: #ffc1c1; stroke-linejoin: miter"/> @@ -31660,12 +31660,12 @@ L 280.37701 415.450029 L 280.646807 415.454074 L 280.916605 415.45646 L 281.186402 415.457242 -" clip-path="url(#p1263779708)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa8dcf6bf44)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa8dcf6bf44)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31683,7 +31683,7 @@ L 310.386555 423.190588 L 310.386555 404.555294 L 286.941176 404.555294 z -" clip-path="url(#p80e7fada6a)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> +" clip-path="url(#pba0d58a58a)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> @@ -31768,12 +31768,12 @@ L 308.511464 415.458474 L 308.781261 415.457783 L 309.051058 415.457376 L 309.320856 415.457242 -" clip-path="url(#p80e7fada6a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pba0d58a58a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pba0d58a58a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31791,7 +31791,7 @@ L 338.521008 423.190588 L 338.521008 404.555294 L 315.07563 404.555294 z -" clip-path="url(#p60265c9164)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> +" clip-path="url(#p85e48c783e)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> @@ -31876,12 +31876,12 @@ L 336.645918 415.473255 L 336.915715 415.464275 L 337.185512 415.458979 L 337.455309 415.457242 -" clip-path="url(#p60265c9164)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p85e48c783e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p85e48c783e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31899,7 +31899,7 @@ L 366.655462 423.190588 L 366.655462 404.555294 L 343.210084 404.555294 z -" clip-path="url(#pa612f05552)" style="fill: #a9a9ff; opacity: 0.5; stroke: #a9a9ff; stroke-linejoin: miter"/> +" clip-path="url(#p38877f9dec)" style="fill: #a9a9ff; opacity: 0.5; stroke: #a9a9ff; stroke-linejoin: miter"/> @@ -31984,12 +31984,12 @@ L 364.780372 415.464478 L 365.050169 415.46042 L 365.319966 415.458027 L 365.589763 415.457242 -" clip-path="url(#pa612f05552)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p38877f9dec)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p38877f9dec)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32007,7 +32007,7 @@ L 394.789916 423.190588 L 394.789916 404.555294 L 371.344538 404.555294 z -" clip-path="url(#p3f6008249c)" style="fill: #ffd5d5; opacity: 0.5; stroke: #ffd5d5; stroke-linejoin: miter"/> +" clip-path="url(#p7cc3fe753b)" style="fill: #ffd5d5; opacity: 0.5; stroke: #ffd5d5; stroke-linejoin: miter"/> @@ -32092,12 +32092,12 @@ L 392.914825 415.449228 L 393.184623 415.453723 L 393.45442 415.456373 L 393.724217 415.457242 -" clip-path="url(#p3f6008249c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7cc3fe753b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7cc3fe753b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32115,7 +32115,7 @@ L 422.92437 423.190588 L 422.92437 404.555294 L 399.478992 404.555294 z -" clip-path="url(#p2269a289e5)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#pe678e41556)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -32200,12 +32200,12 @@ L 421.049279 415.46869 L 421.319076 415.46227 L 421.588874 415.458484 L 421.858671 415.457242 -" clip-path="url(#p2269a289e5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe678e41556)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe678e41556)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32223,7 +32223,7 @@ L 451.058824 423.190588 L 451.058824 404.555294 L 427.613445 404.555294 z -" clip-path="url(#pa1e64b7c44)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#paae62c5eae)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -32308,12 +32308,12 @@ L 449.183733 415.449992 L 449.45353 415.454058 L 449.723327 415.456456 L 449.993125 415.457242 -" clip-path="url(#pa1e64b7c44)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paae62c5eae)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paae62c5eae)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32331,7 +32331,7 @@ L 479.193277 423.190588 L 479.193277 404.555294 L 455.747899 404.555294 z -" clip-path="url(#pe6ba4a3ac6)" style="fill: #ff9999; opacity: 0.5; stroke: #ff9999; stroke-linejoin: miter"/> +" clip-path="url(#pa5b3daa724)" style="fill: #ff9999; opacity: 0.5; stroke: #ff9999; stroke-linejoin: miter"/> @@ -32416,12 +32416,12 @@ L 477.318187 415.457608 L 477.587984 415.457403 L 477.857781 415.457282 L 478.127578 415.457242 -" clip-path="url(#pe6ba4a3ac6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa5b3daa724)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa5b3daa724)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32439,7 +32439,7 @@ L 507.327731 423.190588 L 507.327731 404.555294 L 483.882353 404.555294 z -" clip-path="url(#pf3eb80c03e)" style="fill: #ff6565; opacity: 0.5; stroke: #ff6565; stroke-linejoin: miter"/> +" clip-path="url(#p25fd40c0aa)" style="fill: #ff6565; opacity: 0.5; stroke: #ff6565; stroke-linejoin: miter"/> @@ -32524,12 +32524,12 @@ L 505.45264 415.446837 L 505.722438 415.452672 L 505.992235 415.456113 L 506.262032 415.457242 -" clip-path="url(#pf3eb80c03e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p25fd40c0aa)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p25fd40c0aa)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32547,7 +32547,7 @@ L 535.462185 423.190588 L 535.462185 404.555294 L 512.016807 404.555294 z -" clip-path="url(#p34f40ed1f5)" style="fill: #ff6d6d; opacity: 0.5; stroke: #ff6d6d; stroke-linejoin: miter"/> +" clip-path="url(#p1924177a5f)" style="fill: #ff6d6d; opacity: 0.5; stroke: #ff6d6d; stroke-linejoin: miter"/> @@ -32632,12 +32632,12 @@ L 533.587094 415.454417 L 533.856891 415.456001 L 534.126689 415.456936 L 534.396486 415.457242 -" clip-path="url(#p34f40ed1f5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1924177a5f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1924177a5f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32655,7 +32655,7 @@ L 563.596639 423.190588 L 563.596639 404.555294 L 540.151261 404.555294 z -" clip-path="url(#p0c3f8321fe)" style="fill: #ff9595; opacity: 0.5; stroke: #ff9595; stroke-linejoin: miter"/> +" clip-path="url(#pe4f475e0bc)" style="fill: #ff9595; opacity: 0.5; stroke: #ff9595; stroke-linejoin: miter"/> @@ -32740,12 +32740,12 @@ L 561.721548 415.462082 L 561.991345 415.459368 L 562.261142 415.457767 L 562.53094 415.457242 -" clip-path="url(#p0c3f8321fe)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe4f475e0bc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe4f475e0bc)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32763,7 +32763,7 @@ L 591.731092 423.190588 L 591.731092 404.555294 L 568.285714 404.555294 z -" clip-path="url(#p5765f3f7a6)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> +" clip-path="url(#p45b464a679)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> @@ -32848,12 +32848,12 @@ L 589.856002 415.465855 L 590.125799 415.461025 L 590.395596 415.458177 L 590.665393 415.457242 -" clip-path="url(#p5765f3f7a6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p45b464a679)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p45b464a679)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32871,7 +32871,7 @@ L 619.865546 423.190588 L 619.865546 404.555294 L 596.420168 404.555294 z -" clip-path="url(#pdae4fd27e0)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> +" clip-path="url(#p720c15bc52)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> @@ -32956,12 +32956,12 @@ L 617.990456 415.460143 L 618.260253 415.458516 L 618.53005 415.457557 L 618.799847 415.457242 -" clip-path="url(#pdae4fd27e0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p720c15bc52)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p720c15bc52)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32979,7 +32979,7 @@ L 113.445378 445.552941 L 113.445378 426.917647 L 90 426.917647 z -" clip-path="url(#p3de70c48b7)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> +" clip-path="url(#p477467a738)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> @@ -33064,12 +33064,12 @@ L 111.570287 439.308133 L 111.840085 439.306067 L 112.109882 439.304849 L 112.379679 439.304449 -" clip-path="url(#p3de70c48b7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p477467a738)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p477467a738)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33087,7 +33087,7 @@ L 141.579832 445.552941 L 141.579832 426.917647 L 118.134454 426.917647 z -" clip-path="url(#p1dd1f959c0)" style="fill: #5d5dff; opacity: 0.5; stroke: #5d5dff; stroke-linejoin: miter"/> +" clip-path="url(#pfb9caf8f44)" style="fill: #5d5dff; opacity: 0.5; stroke: #5d5dff; stroke-linejoin: miter"/> @@ -33172,12 +33172,12 @@ L 139.704741 439.317069 L 139.974538 439.309992 L 140.244336 439.305818 L 140.514133 439.304449 -" clip-path="url(#p1dd1f959c0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfb9caf8f44)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfb9caf8f44)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33195,7 +33195,7 @@ L 169.714286 445.552941 L 169.714286 426.917647 L 146.268908 426.917647 z -" clip-path="url(#p3a27242fec)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> +" clip-path="url(#pdd7c4ed883)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> @@ -33280,12 +33280,12 @@ L 167.839195 439.313623 L 168.108992 439.308478 L 168.378789 439.305444 L 168.648587 439.304449 -" clip-path="url(#p3a27242fec)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdd7c4ed883)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdd7c4ed883)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33303,7 +33303,7 @@ L 197.848739 445.552941 L 197.848739 426.917647 L 174.403361 426.917647 z -" clip-path="url(#pc9cb119b7c)" style="fill: #5d5dff; opacity: 0.5; stroke: #5d5dff; stroke-linejoin: miter"/> +" clip-path="url(#p19d5b45545)" style="fill: #5d5dff; opacity: 0.5; stroke: #5d5dff; stroke-linejoin: miter"/> @@ -33388,12 +33388,12 @@ L 195.973649 439.315047 L 196.243446 439.309103 L 196.513243 439.305599 L 196.78304 439.304449 -" clip-path="url(#pc9cb119b7c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p19d5b45545)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p19d5b45545)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33411,7 +33411,7 @@ L 225.983193 445.552941 L 225.983193 426.917647 L 202.537815 426.917647 z -" clip-path="url(#pdd26ef3528)" style="fill: #1919ff; opacity: 0.5; stroke: #1919ff; stroke-linejoin: miter"/> +" clip-path="url(#p594053c304)" style="fill: #1919ff; opacity: 0.5; stroke: #1919ff; stroke-linejoin: miter"/> @@ -33496,12 +33496,12 @@ L 224.108103 439.314875 L 224.3779 439.309028 L 224.647697 439.30558 L 224.917494 439.304449 -" clip-path="url(#pdd26ef3528)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p594053c304)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p594053c304)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33519,7 +33519,7 @@ L 254.117647 445.552941 L 254.117647 426.917647 L 230.672269 426.917647 z -" clip-path="url(#p9fd7a2e406)" style="fill: #4545ff; opacity: 0.5; stroke: #4545ff; stroke-linejoin: miter"/> +" clip-path="url(#p1bff6cd4ce)" style="fill: #4545ff; opacity: 0.5; stroke: #4545ff; stroke-linejoin: miter"/> @@ -33604,12 +33604,12 @@ L 252.242556 439.317818 L 252.512354 439.31032 L 252.782151 439.305899 L 253.051948 439.304449 -" clip-path="url(#p9fd7a2e406)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1bff6cd4ce)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1bff6cd4ce)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33627,7 +33627,7 @@ L 282.252101 445.552941 L 282.252101 426.917647 L 258.806723 426.917647 z -" clip-path="url(#pb01e2149f5)" style="fill: #4949ff; opacity: 0.5; stroke: #4949ff; stroke-linejoin: miter"/> +" clip-path="url(#pf4c515989d)" style="fill: #4949ff; opacity: 0.5; stroke: #4949ff; stroke-linejoin: miter"/> @@ -33712,12 +33712,12 @@ L 280.37701 439.314713 L 280.646807 439.308957 L 280.916605 439.305562 L 281.186402 439.304449 -" clip-path="url(#pb01e2149f5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf4c515989d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf4c515989d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33735,7 +33735,7 @@ L 310.386555 445.552941 L 310.386555 426.917647 L 286.941176 426.917647 z -" clip-path="url(#pf0a2ba9647)" style="fill: #1111ff; opacity: 0.5; stroke: #1111ff; stroke-linejoin: miter"/> +" clip-path="url(#p41bb6ac8fb)" style="fill: #1111ff; opacity: 0.5; stroke: #1111ff; stroke-linejoin: miter"/> @@ -33820,12 +33820,12 @@ L 308.511464 439.316418 L 308.781261 439.309706 L 309.051058 439.305747 L 309.320856 439.304449 -" clip-path="url(#pf0a2ba9647)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p41bb6ac8fb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p41bb6ac8fb)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33843,7 +33843,7 @@ L 338.521008 445.552941 L 338.521008 426.917647 L 315.07563 426.917647 z -" clip-path="url(#p8bf27a509a)" style="fill: #7979ff; opacity: 0.5; stroke: #7979ff; stroke-linejoin: miter"/> +" clip-path="url(#pd70e6a6209)" style="fill: #7979ff; opacity: 0.5; stroke: #7979ff; stroke-linejoin: miter"/> @@ -33928,12 +33928,12 @@ L 336.645918 439.311237 L 336.915715 439.30743 L 337.185512 439.305185 L 337.455309 439.304449 -" clip-path="url(#p8bf27a509a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd70e6a6209)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd70e6a6209)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33951,7 +33951,7 @@ L 366.655462 445.552941 L 366.655462 426.917647 L 343.210084 426.917647 z -" clip-path="url(#p47e5ef91c4)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> +" clip-path="url(#p356c0af8e3)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> @@ -34036,12 +34036,12 @@ L 364.780372 439.304844 L 365.050169 439.304622 L 365.319966 439.304492 L 365.589763 439.304449 -" clip-path="url(#p47e5ef91c4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p356c0af8e3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p356c0af8e3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34059,7 +34059,7 @@ L 394.789916 445.552941 L 394.789916 426.917647 L 371.344538 426.917647 z -" clip-path="url(#p9bf9baac17)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> +" clip-path="url(#p4da39ac640)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> @@ -34144,12 +34144,12 @@ L 392.914825 439.295674 L 393.184623 439.300595 L 393.45442 439.303497 L 393.724217 439.304449 -" clip-path="url(#p9bf9baac17)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4da39ac640)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4da39ac640)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34167,7 +34167,7 @@ L 422.92437 445.552941 L 422.92437 426.917647 L 399.478992 426.917647 z -" clip-path="url(#pc345d8498e)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> +" clip-path="url(#p49d66f28e4)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> @@ -34252,12 +34252,12 @@ L 421.049279 439.313554 L 421.319076 439.308448 L 421.588874 439.305437 L 421.858671 439.304449 -" clip-path="url(#pc345d8498e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p49d66f28e4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p49d66f28e4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34275,7 +34275,7 @@ L 451.058824 445.552941 L 451.058824 426.917647 L 427.613445 426.917647 z -" clip-path="url(#p06aed6c63d)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> +" clip-path="url(#paa1164f8c4)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> @@ -34360,12 +34360,12 @@ L 449.183733 439.296166 L 449.45353 439.300811 L 449.723327 439.30355 L 449.993125 439.304449 -" clip-path="url(#p06aed6c63d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa1164f8c4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa1164f8c4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34383,7 +34383,7 @@ L 479.193277 445.552941 L 479.193277 426.917647 L 455.747899 426.917647 z -" clip-path="url(#p6cd28145cb)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p38f6c08323)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -34468,12 +34468,12 @@ L 477.318187 439.315477 L 477.587984 439.309292 L 477.857781 439.305645 L 478.127578 439.304449 -" clip-path="url(#p6cd28145cb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p38f6c08323)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p38f6c08323)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34491,7 +34491,7 @@ L 507.327731 445.552941 L 507.327731 426.917647 L 483.882353 426.917647 z -" clip-path="url(#p6684d3259d)" style="fill: #ffd5d5; opacity: 0.5; stroke: #ffd5d5; stroke-linejoin: miter"/> +" clip-path="url(#p6e3500356b)" style="fill: #ffd5d5; opacity: 0.5; stroke: #ffd5d5; stroke-linejoin: miter"/> @@ -34576,12 +34576,12 @@ L 505.45264 439.301718 L 505.722438 439.303249 L 505.992235 439.304153 L 506.262032 439.304449 -" clip-path="url(#p6684d3259d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6e3500356b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6e3500356b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34599,7 +34599,7 @@ L 535.462185 445.552941 L 535.462185 426.917647 L 512.016807 426.917647 z -" clip-path="url(#pd9ce16e0d9)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#pe9ed4b5568)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -34684,12 +34684,12 @@ L 533.587094 439.310185 L 533.856891 439.306968 L 534.126689 439.305071 L 534.396486 439.304449 -" clip-path="url(#pd9ce16e0d9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe9ed4b5568)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe9ed4b5568)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34707,7 +34707,7 @@ L 563.596639 445.552941 L 563.596639 426.917647 L 540.151261 426.917647 z -" clip-path="url(#pfb20f86966)" style="fill: #ff7575; opacity: 0.5; stroke: #ff7575; stroke-linejoin: miter"/> +" clip-path="url(#pd4dd9965da)" style="fill: #ff7575; opacity: 0.5; stroke: #ff7575; stroke-linejoin: miter"/> @@ -34792,12 +34792,12 @@ L 561.721548 439.299768 L 561.991345 439.302393 L 562.261142 439.303941 L 562.53094 439.304449 -" clip-path="url(#pfb20f86966)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd4dd9965da)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd4dd9965da)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34815,7 +34815,7 @@ L 591.731092 445.552941 L 591.731092 426.917647 L 568.285714 426.917647 z -" clip-path="url(#p0cfdf8227c)" style="fill: #ff6565; opacity: 0.5; stroke: #ff6565; stroke-linejoin: miter"/> +" clip-path="url(#pab7cd0c028)" style="fill: #ff6565; opacity: 0.5; stroke: #ff6565; stroke-linejoin: miter"/> @@ -34900,12 +34900,12 @@ L 589.856002 439.291944 L 590.125799 439.298957 L 590.395596 439.303092 L 590.665393 439.304449 -" clip-path="url(#p0cfdf8227c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pab7cd0c028)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pab7cd0c028)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34923,7 +34923,7 @@ L 619.865546 445.552941 L 619.865546 426.917647 L 596.420168 426.917647 z -" clip-path="url(#pf8c4036ed5)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p5c17b5836a)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -35008,12 +35008,12 @@ L 617.990456 439.296575 L 618.260253 439.300991 L 618.53005 439.303595 L 618.799847 439.304449 -" clip-path="url(#pf8c4036ed5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5c17b5836a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5c17b5836a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35031,7 +35031,7 @@ L 113.445378 467.915294 L 113.445378 449.28 L 90 449.28 z -" clip-path="url(#pad45e0feef)" style="fill: #7d7dff; opacity: 0.5; stroke: #7d7dff; stroke-linejoin: miter"/> +" clip-path="url(#pfcd64a4992)" style="fill: #7d7dff; opacity: 0.5; stroke: #7d7dff; stroke-linejoin: miter"/> @@ -35116,12 +35116,12 @@ L 111.570287 458.537197 L 111.840085 458.530534 L 112.109882 458.526604 L 112.379679 458.525316 -" clip-path="url(#pad45e0feef)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfcd64a4992)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfcd64a4992)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35139,7 +35139,7 @@ L 141.579832 467.915294 L 141.579832 449.28 L 118.134454 449.28 z -" clip-path="url(#p6f2af10475)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#pcbb50b34b4)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -35224,12 +35224,12 @@ L 139.704741 458.533721 L 139.974538 458.529007 L 140.244336 458.526227 L 140.514133 458.525316 -" clip-path="url(#p6f2af10475)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcbb50b34b4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcbb50b34b4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35247,7 +35247,7 @@ L 169.714286 467.915294 L 169.714286 449.28 L 146.268908 449.28 z -" clip-path="url(#p2accaad9db)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> +" clip-path="url(#p9d71c3e432)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> @@ -35332,12 +35332,12 @@ L 167.839195 458.544241 L 168.108992 458.533628 L 168.378789 458.527369 L 168.648587 458.525316 -" clip-path="url(#p2accaad9db)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9d71c3e432)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9d71c3e432)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35355,7 +35355,7 @@ L 197.848739 467.915294 L 197.848739 449.28 L 174.403361 449.28 z -" clip-path="url(#p397dc7ec51)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#paab8e23e0a)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -35440,12 +35440,12 @@ L 195.973649 458.529259 L 196.243446 458.527048 L 196.513243 458.525743 L 196.78304 458.525316 -" clip-path="url(#p397dc7ec51)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paab8e23e0a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paab8e23e0a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35463,7 +35463,7 @@ L 225.983193 467.915294 L 225.983193 449.28 L 202.537815 449.28 z -" clip-path="url(#pda0b410ff0)" style="fill: #6161ff; opacity: 0.5; stroke: #6161ff; stroke-linejoin: miter"/> +" clip-path="url(#p60df48ef90)" style="fill: #6161ff; opacity: 0.5; stroke: #6161ff; stroke-linejoin: miter"/> @@ -35548,12 +35548,12 @@ L 224.108103 458.544783 L 224.3779 458.533866 L 224.647697 458.527427 L 224.917494 458.525316 -" clip-path="url(#pda0b410ff0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p60df48ef90)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p60df48ef90)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35571,7 +35571,7 @@ L 254.117647 467.915294 L 254.117647 449.28 L 230.672269 449.28 z -" clip-path="url(#p0c0c443c79)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> +" clip-path="url(#p84dda8c28b)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> @@ -35656,12 +35656,12 @@ L 252.242556 458.544207 L 252.512354 458.533612 L 252.782151 458.527365 L 253.051948 458.525316 -" clip-path="url(#p0c0c443c79)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p84dda8c28b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p84dda8c28b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35679,7 +35679,7 @@ L 282.252101 467.915294 L 282.252101 449.28 L 258.806723 449.28 z -" clip-path="url(#p07908e3a39)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> +" clip-path="url(#pcfa3a8427c)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> @@ -35764,12 +35764,12 @@ L 280.37701 458.540776 L 280.646807 458.532106 L 280.916605 458.526993 L 281.186402 458.525316 -" clip-path="url(#p07908e3a39)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcfa3a8427c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcfa3a8427c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35787,7 +35787,7 @@ L 310.386555 467.915294 L 310.386555 449.28 L 286.941176 449.28 z -" clip-path="url(#pe215291557)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> +" clip-path="url(#p55cb3e1f27)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> @@ -35872,12 +35872,12 @@ L 308.511464 458.543034 L 308.781261 458.533098 L 309.051058 458.527238 L 309.320856 458.525316 -" clip-path="url(#pe215291557)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p55cb3e1f27)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p55cb3e1f27)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35895,7 +35895,7 @@ L 338.521008 467.915294 L 338.521008 449.28 L 315.07563 449.28 z -" clip-path="url(#pf56c863331)" style="fill: #7171ff; opacity: 0.5; stroke: #7171ff; stroke-linejoin: miter"/> +" clip-path="url(#pbaae2a8522)" style="fill: #7171ff; opacity: 0.5; stroke: #7171ff; stroke-linejoin: miter"/> @@ -35980,12 +35980,12 @@ L 336.645918 458.551909 L 336.915715 458.536996 L 337.185512 458.5282 L 337.455309 458.525316 -" clip-path="url(#pf56c863331)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbaae2a8522)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbaae2a8522)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36003,7 +36003,7 @@ L 366.655462 467.915294 L 366.655462 449.28 L 343.210084 449.28 z -" clip-path="url(#p77cd95097f)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> +" clip-path="url(#pd2d75695f6)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> @@ -36088,12 +36088,12 @@ L 364.780372 458.545604 L 365.050169 458.534226 L 365.319966 458.527516 L 365.589763 458.525316 -" clip-path="url(#p77cd95097f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd2d75695f6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd2d75695f6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36111,7 +36111,7 @@ L 394.789916 467.915294 L 394.789916 449.28 L 371.344538 449.28 z -" clip-path="url(#pc42a660ef4)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> +" clip-path="url(#p56c03cde85)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> @@ -36196,12 +36196,12 @@ L 392.914825 458.533235 L 393.184623 458.528794 L 393.45442 458.526175 L 393.724217 458.525316 -" clip-path="url(#pc42a660ef4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p56c03cde85)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p56c03cde85)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36219,7 +36219,7 @@ L 422.92437 467.915294 L 422.92437 449.28 L 399.478992 449.28 z -" clip-path="url(#pa7e354b83a)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> +" clip-path="url(#p3f7bed994f)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> @@ -36304,12 +36304,12 @@ L 421.049279 458.530407 L 421.319076 458.527552 L 421.588874 458.525868 L 421.858671 458.525316 -" clip-path="url(#pa7e354b83a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3f7bed994f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3f7bed994f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36327,7 +36327,7 @@ L 451.058824 467.915294 L 451.058824 449.28 L 427.613445 449.28 z -" clip-path="url(#p8ec0e7132d)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> +" clip-path="url(#p407d5355da)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> @@ -36412,12 +36412,12 @@ L 449.183733 458.516273 L 449.45353 458.521344 L 449.723327 458.524335 L 449.993125 458.525316 -" clip-path="url(#p8ec0e7132d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p407d5355da)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p407d5355da)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36435,7 +36435,7 @@ L 479.193277 467.915294 L 479.193277 449.28 L 455.747899 449.28 z -" clip-path="url(#p1564a41dbd)" style="fill: #ffeded; opacity: 0.5; stroke: #ffeded; stroke-linejoin: miter"/> +" clip-path="url(#pfa8eee058a)" style="fill: #ffeded; opacity: 0.5; stroke: #ffeded; stroke-linejoin: miter"/> @@ -36520,12 +36520,12 @@ L 477.318187 458.520706 L 477.587984 458.523291 L 477.857781 458.524815 L 478.127578 458.525316 -" clip-path="url(#p1564a41dbd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfa8eee058a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfa8eee058a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36543,7 +36543,7 @@ L 507.327731 467.915294 L 507.327731 449.28 L 483.882353 449.28 z -" clip-path="url(#pf40080e462)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> +" clip-path="url(#pab5b2207b3)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> @@ -36628,12 +36628,12 @@ L 505.45264 458.515312 L 505.722438 458.520922 L 505.992235 458.52423 L 506.262032 458.525316 -" clip-path="url(#pf40080e462)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pab5b2207b3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pab5b2207b3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36651,7 +36651,7 @@ L 535.462185 467.915294 L 535.462185 449.28 L 512.016807 449.28 z -" clip-path="url(#p03d6232c99)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> +" clip-path="url(#p3a1d07f080)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> @@ -36736,12 +36736,12 @@ L 533.587094 458.534952 L 533.856891 458.529548 L 534.126689 458.526361 L 534.396486 458.525316 -" clip-path="url(#p03d6232c99)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3a1d07f080)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3a1d07f080)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36759,7 +36759,7 @@ L 563.596639 467.915294 L 563.596639 449.28 L 540.151261 449.28 z -" clip-path="url(#p1897ee2d27)" style="fill: #ffeded; opacity: 0.5; stroke: #ffeded; stroke-linejoin: miter"/> +" clip-path="url(#pf7b7c8e2eb)" style="fill: #ffeded; opacity: 0.5; stroke: #ffeded; stroke-linejoin: miter"/> @@ -36844,12 +36844,12 @@ L 561.721548 458.523184 L 561.991345 458.524379 L 562.261142 458.525084 L 562.53094 458.525316 -" clip-path="url(#p1897ee2d27)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf7b7c8e2eb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf7b7c8e2eb)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36867,7 +36867,7 @@ L 591.731092 467.915294 L 591.731092 449.28 L 568.285714 449.28 z -" clip-path="url(#peb40f8c2ec)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p7385683ca4)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -36952,12 +36952,12 @@ L 589.856002 458.500033 L 590.125799 458.514211 L 590.395596 458.522573 L 590.665393 458.525316 -" clip-path="url(#peb40f8c2ec)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7385683ca4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7385683ca4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36975,7 +36975,7 @@ L 619.865546 467.915294 L 619.865546 449.28 L 596.420168 449.28 z -" clip-path="url(#p0aab5aa473)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> +" clip-path="url(#p41ded0743a)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> @@ -37060,12 +37060,12 @@ L 617.990456 458.508604 L 618.260253 458.517976 L 618.53005 458.523503 L 618.799847 458.525316 -" clip-path="url(#p0aab5aa473)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p41ded0743a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p41ded0743a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37083,7 +37083,7 @@ L 113.445378 490.277647 L 113.445378 471.642353 L 90 471.642353 z -" clip-path="url(#pae31175321)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> +" clip-path="url(#p5f3dc98fe8)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> @@ -37168,12 +37168,12 @@ L 111.570287 481.165739 L 111.840085 481.163532 L 112.109882 481.162231 L 112.379679 481.161804 -" clip-path="url(#pae31175321)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5f3dc98fe8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5f3dc98fe8)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37191,7 +37191,7 @@ L 141.579832 490.277647 L 141.579832 471.642353 L 118.134454 471.642353 z -" clip-path="url(#pc41c6b7ba7)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> +" clip-path="url(#p1fbe971d18)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> @@ -37276,12 +37276,12 @@ L 139.704741 481.164234 L 139.974538 481.162871 L 140.244336 481.162068 L 140.514133 481.161804 -" clip-path="url(#pc41c6b7ba7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1fbe971d18)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1fbe971d18)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37299,7 +37299,7 @@ L 169.714286 490.277647 L 169.714286 471.642353 L 146.268908 471.642353 z -" clip-path="url(#p29160fd78a)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> +" clip-path="url(#pa906890f7c)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> @@ -37384,12 +37384,12 @@ L 167.839195 481.165936 L 168.108992 481.163619 L 168.378789 481.162252 L 168.648587 481.161804 -" clip-path="url(#p29160fd78a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa906890f7c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa906890f7c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37407,7 +37407,7 @@ L 197.848739 490.277647 L 197.848739 471.642353 L 174.403361 471.642353 z -" clip-path="url(#pdf66c5d7d5)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#p31b2cf25dd)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -37492,12 +37492,12 @@ L 195.973649 481.1597 L 196.243446 481.16088 L 196.513243 481.161576 L 196.78304 481.161804 -" clip-path="url(#pdf66c5d7d5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p31b2cf25dd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p31b2cf25dd)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37515,7 +37515,7 @@ L 225.983193 490.277647 L 225.983193 471.642353 L 202.537815 471.642353 z -" clip-path="url(#p9752e93e8b)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> +" clip-path="url(#p9d61a3ea6d)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> @@ -37600,12 +37600,12 @@ L 224.108103 481.172929 L 224.3779 481.16669 L 224.647697 481.163011 L 224.917494 481.161804 -" clip-path="url(#p9752e93e8b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9d61a3ea6d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9d61a3ea6d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37623,7 +37623,7 @@ L 254.117647 490.277647 L 254.117647 471.642353 L 230.672269 471.642353 z -" clip-path="url(#pf47c27d5ac)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> +" clip-path="url(#pb908068de3)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> @@ -37708,12 +37708,12 @@ L 252.242556 481.170119 L 252.512354 481.165456 L 252.782151 481.162706 L 253.051948 481.161804 -" clip-path="url(#pf47c27d5ac)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb908068de3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb908068de3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37731,7 +37731,7 @@ L 282.252101 490.277647 L 282.252101 471.642353 L 258.806723 471.642353 z -" clip-path="url(#pa04dc76dd1)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#p94cb45794f)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -37816,12 +37816,12 @@ L 280.37701 481.173222 L 280.646807 481.166819 L 280.916605 481.163043 L 281.186402 481.161804 -" clip-path="url(#pa04dc76dd1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p94cb45794f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p94cb45794f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37839,7 +37839,7 @@ L 310.386555 490.277647 L 310.386555 471.642353 L 286.941176 471.642353 z -" clip-path="url(#p4f0022747c)" style="fill: #a9a9ff; opacity: 0.5; stroke: #a9a9ff; stroke-linejoin: miter"/> +" clip-path="url(#p1a1be426ca)" style="fill: #a9a9ff; opacity: 0.5; stroke: #a9a9ff; stroke-linejoin: miter"/> @@ -37924,12 +37924,12 @@ L 308.511464 481.176262 L 308.781261 481.168154 L 309.051058 481.163373 L 309.320856 481.161804 -" clip-path="url(#p4f0022747c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1a1be426ca)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1a1be426ca)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37947,7 +37947,7 @@ L 338.521008 490.277647 L 338.521008 471.642353 L 315.07563 471.642353 z -" clip-path="url(#pca9d192d86)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> +" clip-path="url(#p9f9733bcea)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> @@ -38032,12 +38032,12 @@ L 336.645918 481.180929 L 336.915715 481.170204 L 337.185512 481.163879 L 337.455309 481.161804 -" clip-path="url(#pca9d192d86)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9f9733bcea)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9f9733bcea)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38055,7 +38055,7 @@ L 366.655462 490.277647 L 366.655462 471.642353 L 343.210084 471.642353 z -" clip-path="url(#pd830fa49e2)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> +" clip-path="url(#p2d10916a10)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> @@ -38140,12 +38140,12 @@ L 364.780372 481.178016 L 365.050169 481.168924 L 365.319966 481.163563 L 365.589763 481.161804 -" clip-path="url(#pd830fa49e2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d10916a10)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2d10916a10)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38163,7 +38163,7 @@ L 394.789916 490.277647 L 394.789916 471.642353 L 371.344538 471.642353 z -" clip-path="url(#p4f6b64c505)" style="fill: #5959ff; opacity: 0.5; stroke: #5959ff; stroke-linejoin: miter"/> +" clip-path="url(#p9b39222a60)" style="fill: #5959ff; opacity: 0.5; stroke: #5959ff; stroke-linejoin: miter"/> @@ -38248,12 +38248,12 @@ L 392.914825 481.18662 L 393.184623 481.172703 L 393.45442 481.164496 L 393.724217 481.161804 -" clip-path="url(#p4f6b64c505)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9b39222a60)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9b39222a60)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38271,7 +38271,7 @@ L 422.92437 490.277647 L 422.92437 471.642353 L 399.478992 471.642353 z -" clip-path="url(#p91102d22a9)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> +" clip-path="url(#p6e4fe96cb2)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> @@ -38356,12 +38356,12 @@ L 421.049279 481.167207 L 421.319076 481.164177 L 421.588874 481.16239 L 421.858671 481.161804 -" clip-path="url(#p91102d22a9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6e4fe96cb2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6e4fe96cb2)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38379,7 +38379,7 @@ L 451.058824 490.277647 L 451.058824 471.642353 L 427.613445 471.642353 z -" clip-path="url(#p955872868e)" style="fill: #ff7575; opacity: 0.5; stroke: #ff7575; stroke-linejoin: miter"/> +" clip-path="url(#p3e427179b5)" style="fill: #ff7575; opacity: 0.5; stroke: #ff7575; stroke-linejoin: miter"/> @@ -38464,12 +38464,12 @@ L 449.183733 481.145069 L 449.45353 481.154454 L 449.723327 481.159989 L 449.993125 481.161804 -" clip-path="url(#p955872868e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3e427179b5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3e427179b5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38487,7 +38487,7 @@ L 479.193277 490.277647 L 479.193277 471.642353 L 455.747899 471.642353 z -" clip-path="url(#p48d5067782)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> +" clip-path="url(#p0dba311d5a)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> @@ -38572,12 +38572,12 @@ L 477.318187 481.167085 L 477.587984 481.164123 L 477.857781 481.162377 L 478.127578 481.161804 -" clip-path="url(#p48d5067782)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0dba311d5a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0dba311d5a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38595,7 +38595,7 @@ L 507.327731 490.277647 L 507.327731 471.642353 L 483.882353 471.642353 z -" clip-path="url(#p6aaebb25f1)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> +" clip-path="url(#p2617c1d1a5)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> @@ -38680,12 +38680,12 @@ L 505.45264 481.174124 L 505.722438 481.167215 L 505.992235 481.163141 L 506.262032 481.161804 -" clip-path="url(#p6aaebb25f1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2617c1d1a5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2617c1d1a5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38703,7 +38703,7 @@ L 535.462185 490.277647 L 535.462185 471.642353 L 512.016807 471.642353 z -" clip-path="url(#p3f9661e63a)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#p035801f782)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -38788,12 +38788,12 @@ L 533.587094 481.163328 L 533.856891 481.162473 L 534.126689 481.161969 L 534.396486 481.161804 -" clip-path="url(#p3f9661e63a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p035801f782)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p035801f782)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38811,7 +38811,7 @@ L 563.596639 490.277647 L 563.596639 471.642353 L 540.151261 471.642353 z -" clip-path="url(#p3fd435794b)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#p89a08212c3)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -38896,12 +38896,12 @@ L 561.721548 481.152977 L 561.991345 481.157927 L 562.261142 481.160847 L 562.53094 481.161804 -" clip-path="url(#p3fd435794b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p89a08212c3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p89a08212c3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38919,7 +38919,7 @@ L 591.731092 490.277647 L 591.731092 471.642353 L 568.285714 471.642353 z -" clip-path="url(#pa4017c7e65)" style="fill: #ff6969; opacity: 0.5; stroke: #ff6969; stroke-linejoin: miter"/> +" clip-path="url(#p5a3eef6f55)" style="fill: #ff6969; opacity: 0.5; stroke: #ff6969; stroke-linejoin: miter"/> @@ -39004,12 +39004,12 @@ L 589.856002 481.149053 L 590.125799 481.156204 L 590.395596 481.160421 L 590.665393 481.161804 -" clip-path="url(#pa4017c7e65)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5a3eef6f55)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5a3eef6f55)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -39027,7 +39027,7 @@ L 619.865546 490.277647 L 619.865546 471.642353 L 596.420168 471.642353 z -" clip-path="url(#p508d5407d7)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p7f45f008a5)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -39112,12 +39112,12 @@ L 617.990456 481.143418 L 618.260253 481.153729 L 618.53005 481.15981 L 618.799847 481.161804 -" clip-path="url(#p508d5407d7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7f45f008a5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7f45f008a5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -39173,7 +39173,7 @@ z - - - + + @@ -39368,7 +39368,7 @@ z - - - + + @@ -39563,7 +39563,7 @@ z - - - + + @@ -39758,7 +39758,7 @@ z - - - + + @@ -39953,7 +39953,7 @@ z - - - + + @@ -40148,7 +40148,7 @@ z - - - + + @@ -40343,7 +40343,7 @@ z - - - + + @@ -40538,7 +40538,7 @@ z - - - + + @@ -40733,7 +40733,7 @@ z - - - + + @@ -40928,7 +40928,7 @@ z - - - + + @@ -41123,7 +41123,7 @@ z - - - + + @@ -41318,7 +41318,7 @@ z - - - + + @@ -41513,7 +41513,7 @@ z - - - + + @@ -41708,7 +41708,7 @@ z - - - + + @@ -41903,7 +41903,7 @@ z - - - + + @@ -42098,7 +42098,7 @@ z - - - + + @@ -42293,7 +42293,7 @@ z - - - + + @@ -42488,7 +42488,7 @@ z - - - + + @@ -42683,7 +42683,7 @@ z - - - + + @@ -42878,7 +42878,7 @@ z - - - + + @@ -43073,7 +43073,7 @@ z - - - + + @@ -43268,7 +43268,7 @@ z - - - + + @@ -43463,7 +43463,7 @@ z - - - + + @@ -43658,7 +43658,7 @@ z - - - + + @@ -43853,7 +43853,7 @@ z - - - + + @@ -44048,7 +44048,7 @@ z - - - + + @@ -44243,7 +44243,7 @@ z - - - + + @@ -44438,7 +44438,7 @@ z - - - + + @@ -44725,7 +44725,7 @@ z - - - + + @@ -44920,7 +44920,7 @@ z - - - + + @@ -45115,7 +45115,7 @@ z - - - + + @@ -45310,7 +45310,7 @@ z - - - + + @@ -45505,7 +45505,7 @@ z - - - + + @@ -45700,7 +45700,7 @@ z - - - + + @@ -45895,7 +45895,7 @@ z - - - + + @@ -46090,7 +46090,7 @@ z - - - + + @@ -46285,7 +46285,7 @@ z - - - + + @@ -46480,7 +46480,7 @@ z - - - + + @@ -46783,1090 +46783,1090 @@ z - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - 2024-11-21T17:17:54.612554 + 2024-11-21T17:26:20.009910 image/svg+xml @@ -37,20 +37,20 @@ L 47.783588 53.206588 z " style="fill: #ffffff"/> - + +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" id="image7b2bad116d" transform="scale(1 -1) translate(0 -219.6)" x="47.783588" y="-52.929412" width="219.6" height="219.6"/> - - + @@ -86,7 +86,7 @@ z - + @@ -125,7 +125,7 @@ z - + @@ -159,7 +159,7 @@ z - + @@ -204,7 +204,7 @@ z - + @@ -258,7 +258,7 @@ z - + @@ -290,12 +290,12 @@ z - - + @@ -308,7 +308,7 @@ L -3.5 0 - + @@ -321,7 +321,7 @@ L -3.5 0 - + @@ -334,7 +334,7 @@ L -3.5 0 - + @@ -347,7 +347,7 @@ L -3.5 0 - + @@ -360,7 +360,7 @@ L -3.5 0 - + @@ -632,15 +632,15 @@ L 332.183588 53.206588 z " style="fill: #ffffff"/> - + +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" id="image011efcaea0" transform="scale(1 -1) translate(0 -219.6)" x="332.183588" y="-52.929412" width="219.6" height="219.6"/> - + @@ -653,7 +653,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -666,7 +666,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -679,7 +679,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -692,7 +692,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -705,7 +705,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -721,7 +721,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -734,7 +734,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -747,7 +747,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -760,7 +760,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -773,7 +773,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -786,7 +786,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -1019,15 +1019,15 @@ L 616.583588 53.206588 z " style="fill: #ffffff"/> - + +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" id="image27d07cc9ff" transform="scale(1 -1) translate(0 -219.6)" x="616.583588" y="-52.929412" width="219.6" height="219.6"/> - + @@ -1040,7 +1040,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1053,7 +1053,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1066,7 +1066,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1079,7 +1079,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1092,7 +1092,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1108,7 +1108,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1121,7 +1121,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1134,7 +1134,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1147,7 +1147,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1160,7 +1160,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1173,7 +1173,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1335,13 +1335,13 @@ z - + - + - + diff --git a/docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg b/docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg index d8f500d8..b5208833 100644 --- a/docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg +++ b/docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:10:48.342940 + 2024-11-21T17:26:35.023278 image/svg+xml @@ -37,20 +37,20 @@ L 36.72 34.56 z " style="fill: #ffffff"/> - + +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" id="imagea903c28a1e" transform="scale(1 -1) translate(0 -221.76)" x="36.72" y="-34.56" width="221.76" height="221.76"/> - - + @@ -86,7 +86,7 @@ z - + @@ -116,7 +116,7 @@ z - + @@ -156,7 +156,7 @@ z - + @@ -204,7 +204,7 @@ z - + @@ -239,7 +239,7 @@ z - + @@ -282,12 +282,12 @@ z - - + @@ -300,7 +300,7 @@ L -3.5 0 - + @@ -314,7 +314,7 @@ L -3.5 0 - + @@ -328,7 +328,7 @@ L -3.5 0 - + @@ -342,7 +342,7 @@ L -3.5 0 - + @@ -356,7 +356,7 @@ L -3.5 0 - + @@ -381,7 +381,7 @@ L 258.48 256.32 - + diff --git a/docs/assets/thumbnails/tutorials/plot_05_place_cells.svg b/docs/assets/thumbnails/tutorials/plot_05_place_cells.svg index c089d9e7..129e2251 100644 --- a/docs/assets/thumbnails/tutorials/plot_05_place_cells.svg +++ b/docs/assets/thumbnails/tutorials/plot_05_place_cells.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:11:02.852574 + 2024-11-21T17:26:49.366255 image/svg+xml @@ -141,7 +141,7 @@ L 163.282375 89.992092 L 150.859369 90.452067 L 138.436364 86.592956 z -" clip-path="url(#p0e3c4db3b6)" style="fill: #1f77b4"/> +" clip-path="url(#p2a1ea0cd24)" style="fill: #1f77b4"/> @@ -269,7 +269,7 @@ L 163.282375 95.546095 L 150.859369 95.546095 L 138.436364 91.686983 z -" clip-path="url(#pf0e2cb30bb)" style="fill: #1f77b4"/> +" clip-path="url(#pb65756ce19)" style="fill: #1f77b4"/> @@ -397,7 +397,7 @@ L 163.282375 98.516288 L 150.859369 97.387854 L 138.436364 96.781011 z -" clip-path="url(#pa2e8401478)" style="fill: #1f77b4"/> +" clip-path="url(#pc84646f90c)" style="fill: #1f77b4"/> @@ -525,7 +525,7 @@ L 163.282375 105.128713 L 150.859369 103.78146 L 138.436364 101.875038 z -" clip-path="url(#pdc2a28f725)" style="fill: #1f77b4"/> +" clip-path="url(#p57b85ad532)" style="fill: #1f77b4"/> @@ -653,7 +653,7 @@ L 163.282375 109.944734 L 150.859369 108.163866 L 138.436364 106.969066 z -" clip-path="url(#p6d2a2cf141)" style="fill: #1f77b4"/> +" clip-path="url(#p70f5f4ec01)" style="fill: #1f77b4"/> @@ -781,7 +781,7 @@ L 163.282375 112.873397 L 150.859369 112.335632 L 138.436364 112.063093 z -" clip-path="url(#pa20cedf5e1)" style="fill: #1f77b4"/> +" clip-path="url(#pa5fce1bda9)" style="fill: #1f77b4"/> @@ -909,7 +909,7 @@ L 163.282375 119.118836 L 150.859369 117.422188 L 138.436364 117.157121 z -" clip-path="url(#p7f08843877)" style="fill: #1f77b4"/> +" clip-path="url(#pf4593df426)" style="fill: #1f77b4"/> @@ -1037,7 +1037,7 @@ L 163.282375 124.866066 L 150.859369 123.148398 L 138.436364 122.251149 z -" clip-path="url(#pf5ed78058e)" style="fill: #1f77b4"/> +" clip-path="url(#p106130fc18)" style="fill: #1f77b4"/> @@ -1165,7 +1165,7 @@ L 163.282375 130.031018 L 150.859369 128.568937 L 138.436364 127.345176 z -" clip-path="url(#pe043fdbffb)" style="fill: #1f77b4"/> +" clip-path="url(#pc950e56111)" style="fill: #1f77b4"/> @@ -1293,7 +1293,7 @@ L 163.282375 134.247076 L 150.859369 133.904036 L 138.436364 132.439204 z -" clip-path="url(#pf135300692)" style="fill: #1f77b4"/> +" clip-path="url(#p50b0c8bf60)" style="fill: #1f77b4"/> @@ -1421,7 +1421,7 @@ L 163.282375 138.321252 L 150.859369 137.533231 L 138.436364 138.872534 z -" clip-path="url(#pcb1b8af3f4)" style="fill: #1f77b4"/> +" clip-path="url(#pf0aafcc34f)" style="fill: #1f77b4"/> @@ -1549,7 +1549,7 @@ L 163.282375 143.018307 L 150.859369 142.627259 L 138.436364 143.441972 z -" clip-path="url(#p632a40123f)" style="fill: #1f77b4"/> +" clip-path="url(#p98a91c8a49)" style="fill: #1f77b4"/> @@ -1677,7 +1677,7 @@ L 163.282375 147.721286 L 150.859369 149.890333 L 138.436364 150.910121 z -" clip-path="url(#p4f18ef3499)" style="fill: #1f77b4"/> +" clip-path="url(#pb09f3886f3)" style="fill: #1f77b4"/> @@ -1805,7 +1805,7 @@ L 163.282375 152.815314 L 150.859369 154.134299 L 138.436364 155.833457 z -" clip-path="url(#pac2f680d9c)" style="fill: #1f77b4"/> +" clip-path="url(#p6d1020c618)" style="fill: #1f77b4"/> @@ -1933,7 +1933,7 @@ L 163.282375 157.909342 L 150.859369 160.154496 L 138.436364 161.474114 z -" clip-path="url(#pf83d055c07)" style="fill: #1f77b4"/> +" clip-path="url(#p8b9b9b6f0a)" style="fill: #1f77b4"/> @@ -2061,7 +2061,7 @@ L 163.282375 163.003369 L 150.859369 164.886826 L 138.436364 165.554307 z -" clip-path="url(#p038e4ff393)" style="fill: #1f77b4"/> +" clip-path="url(#pc985119a00)" style="fill: #1f77b4"/> @@ -2189,7 +2189,7 @@ L 163.282375 168.097397 L 150.859369 169.511636 L 138.436364 171.404623 z -" clip-path="url(#p09f1676ff4)" style="fill: #1f77b4"/> +" clip-path="url(#pc274d882b6)" style="fill: #1f77b4"/> @@ -2317,7 +2317,7 @@ L 163.282375 174.434254 L 150.859369 173.77534 L 138.436364 174.716213 z -" clip-path="url(#p86f59c37d1)" style="fill: #1f77b4"/> +" clip-path="url(#p85bfd8ab4a)" style="fill: #1f77b4"/> @@ -2445,7 +2445,7 @@ L 163.282375 179.441196 L 150.859369 178.610596 L 138.436364 180.43751 z -" clip-path="url(#peaa58a2cc3)" style="fill: #1f77b4"/> +" clip-path="url(#pfab650f10b)" style="fill: #1f77b4"/> @@ -2573,7 +2573,7 @@ L 163.282375 184.220139 L 150.859369 185.504664 L 138.436364 185.803448 z -" clip-path="url(#p29cbbe9ac5)" style="fill: #1f77b4"/> +" clip-path="url(#paeecc61426)" style="fill: #1f77b4"/> @@ -2701,7 +2701,7 @@ L 163.282375 189.151042 L 150.859369 189.321551 L 138.436364 189.774823 z -" clip-path="url(#pa7d34e827e)" style="fill: #1f77b4"/> +" clip-path="url(#p9109397137)" style="fill: #1f77b4"/> @@ -2829,7 +2829,7 @@ L 163.282375 193.999387 L 150.859369 193.917508 L 138.436364 195.393527 z -" clip-path="url(#pdadc6caba6)" style="fill: #1f77b4"/> +" clip-path="url(#pc8faa3b1c4)" style="fill: #1f77b4"/> @@ -2957,7 +2957,7 @@ L 163.282375 199.083864 L 150.859369 199.861339 L 138.436364 201.34009 z -" clip-path="url(#pc8d9835216)" style="fill: #1f77b4"/> +" clip-path="url(#p9d8a755184)" style="fill: #1f77b4"/> @@ -3085,7 +3085,7 @@ L 163.282375 204.409595 L 150.859369 204.626847 L 138.436364 205.752847 z -" clip-path="url(#p8e16da2b72)" style="fill: #1f77b4"/> +" clip-path="url(#paadc903ea8)" style="fill: #1f77b4"/> @@ -3213,7 +3213,7 @@ L 163.282375 211.436043 L 150.859369 211.457761 L 138.436364 211.187977 z -" clip-path="url(#p18c5b61c55)" style="fill: #1f77b4"/> +" clip-path="url(#p56673c467c)" style="fill: #1f77b4"/> @@ -3341,7 +3341,7 @@ L 163.282375 216.648408 L 150.859369 216.35221 L 138.436364 217.0824 z -" clip-path="url(#p254d2ae3ee)" style="fill: #1f77b4"/> +" clip-path="url(#p9c5d09e342)" style="fill: #1f77b4"/> @@ -3469,7 +3469,7 @@ L 163.282375 219.96929 L 150.859369 220.341077 L 138.436364 221.536938 z -" clip-path="url(#p22082e1379)" style="fill: #1f77b4"/> +" clip-path="url(#pf050b10dd5)" style="fill: #1f77b4"/> @@ -3597,7 +3597,7 @@ L 163.282375 226.523396 L 150.859369 226.543693 L 138.436364 226.930503 z -" clip-path="url(#p41357bc99b)" style="fill: #1f77b4"/> +" clip-path="url(#p3defb47ea2)" style="fill: #1f77b4"/> @@ -3725,7 +3725,7 @@ L 163.282375 231.091986 L 150.859369 230.330212 L 138.436364 232.134856 z -" clip-path="url(#pd005daddb9)" style="fill: #1f77b4"/> +" clip-path="url(#p06f6176b03)" style="fill: #1f77b4"/> @@ -3853,7 +3853,7 @@ L 163.282375 236.953139 L 150.859369 237.117517 L 138.436364 237.372938 z -" clip-path="url(#p9980bdc2c9)" style="fill: #1f77b4"/> +" clip-path="url(#p5592a74c04)" style="fill: #1f77b4"/> @@ -3981,7 +3981,7 @@ L 163.282375 242.633186 L 150.859369 242.314969 L 138.436364 242.84597 z -" clip-path="url(#p8c674b7111)" style="fill: #1f77b4"/> +" clip-path="url(#p41ae79cc8d)" style="fill: #1f77b4"/> @@ -4109,7 +4109,7 @@ L 163.282375 248.182006 L 150.859369 247.514921 L 138.436364 246.392398 z -" clip-path="url(#p6757dd4eec)" style="fill: #1f77b4"/> +" clip-path="url(#p4259896e41)" style="fill: #1f77b4"/> @@ -4237,7 +4237,7 @@ L 163.282375 252.788528 L 150.859369 252.345603 L 138.436364 253.460949 z -" clip-path="url(#p385b3ce1d3)" style="fill: #1f77b4"/> +" clip-path="url(#p20ed02ef01)" style="fill: #1f77b4"/> @@ -4365,7 +4365,7 @@ L 163.282375 258.2069 L 150.859369 258.378563 L 138.436364 258.342591 z -" clip-path="url(#pe32d81a0d7)" style="fill: #1f77b4"/> +" clip-path="url(#p44df880763)" style="fill: #1f77b4"/> @@ -4493,7 +4493,7 @@ L 163.282375 261.873813 L 150.859369 262.194923 L 138.436364 262.926893 z -" clip-path="url(#p2f60b72342)" style="fill: #1f77b4"/> +" clip-path="url(#p49d739a855)" style="fill: #1f77b4"/> @@ -4621,7 +4621,7 @@ L 163.282375 268.436002 L 150.859369 268.640149 L 138.436364 268.668522 z -" clip-path="url(#p8b8d832aa4)" style="fill: #1f77b4"/> +" clip-path="url(#p91c102067c)" style="fill: #1f77b4"/> @@ -4749,7 +4749,7 @@ L 163.282375 272.736498 L 150.859369 273.112653 L 138.436364 273.177522 z -" clip-path="url(#pe569db8b33)" style="fill: #1f77b4"/> +" clip-path="url(#p568845cbc6)" style="fill: #1f77b4"/> @@ -4877,7 +4877,7 @@ L 163.282375 278.50536 L 150.859369 278.27724 L 138.436364 278.60638 z -" clip-path="url(#p997f2efd30)" style="fill: #1f77b4"/> +" clip-path="url(#pfe369ca5c6)" style="fill: #1f77b4"/> @@ -5005,7 +5005,7 @@ L 163.282375 280.96861 L 150.859369 280.997298 L 138.436364 282.101848 z -" clip-path="url(#p29c64d0a0a)" style="fill: #1f77b4"/> +" clip-path="url(#p91f62c74fd)" style="fill: #1f77b4"/> @@ -5133,7 +5133,7 @@ L 163.282375 288.899983 L 150.859369 289.119142 L 138.436364 289.119142 z -" clip-path="url(#p89841cc475)" style="fill: #1f77b4"/> +" clip-path="url(#pd246a78a7e)" style="fill: #1f77b4"/> @@ -5261,7 +5261,7 @@ L 163.282375 291.583257 L 150.859369 293.001435 L 138.436364 293.711703 z -" clip-path="url(#p919af6800c)" style="fill: #1f77b4"/> +" clip-path="url(#pcd250c6099)" style="fill: #1f77b4"/> @@ -5389,7 +5389,7 @@ L 163.282375 299.142828 L 150.859369 299.155731 L 138.436364 299.307198 z -" clip-path="url(#pe1ecb1d528)" style="fill: #1f77b4"/> +" clip-path="url(#p28a991e51a)" style="fill: #1f77b4"/> @@ -5517,7 +5517,7 @@ L 163.282375 303.68113 L 150.859369 304.055015 L 138.436364 304.257949 z -" clip-path="url(#p9afb1a7ac7)" style="fill: #1f77b4"/> +" clip-path="url(#pbaf40ecbb6)" style="fill: #1f77b4"/> @@ -5645,7 +5645,7 @@ L 163.282375 308.595546 L 150.859369 308.857498 L 138.436364 309.284109 z -" clip-path="url(#pbceb632149)" style="fill: #1f77b4"/> +" clip-path="url(#p085006927c)" style="fill: #1f77b4"/> @@ -5773,7 +5773,7 @@ L 163.282375 314.556022 L 150.859369 314.558632 L 138.436364 314.58928 z -" clip-path="url(#pb1f81209a8)" style="fill: #1f77b4"/> +" clip-path="url(#p93d218b450)" style="fill: #1f77b4"/> @@ -5901,7 +5901,7 @@ L 163.282375 319.683308 L 150.859369 319.611416 L 138.436364 319.445293 z -" clip-path="url(#pad345cccfb)" style="fill: #1f77b4"/> +" clip-path="url(#pf3f8024fc5)" style="fill: #1f77b4"/> @@ -6029,7 +6029,7 @@ L 163.282375 324.588668 L 150.859369 324.603478 L 138.436364 324.597462 z -" clip-path="url(#p95e4e3f925)" style="fill: #1f77b4"/> +" clip-path="url(#p50ddab2ee4)" style="fill: #1f77b4"/> @@ -6157,7 +6157,7 @@ L 163.282375 329.71414 L 150.859369 329.146956 L 138.436364 326.393802 z -" clip-path="url(#p2305b25473)" style="fill: #1f77b4"/> +" clip-path="url(#p818c8747cd)" style="fill: #1f77b4"/> @@ -6285,7 +6285,7 @@ L 163.282375 334.521814 L 150.859369 334.515759 L 138.436364 334.62707 z -" clip-path="url(#pb88177550f)" style="fill: #1f77b4"/> +" clip-path="url(#p16be4d8e84)" style="fill: #1f77b4"/> @@ -6413,7 +6413,7 @@ L 163.282375 340.059418 L 150.859369 339.532577 L 138.436364 339.841389 z -" clip-path="url(#p6499365c8e)" style="fill: #1f77b4"/> +" clip-path="url(#p3e9ba3754e)" style="fill: #1f77b4"/> @@ -6541,7 +6541,7 @@ L 163.282375 344.702088 L 150.859369 344.848432 L 138.436364 344.946892 z -" clip-path="url(#p4ee8bd8c39)" style="fill: #1f77b4"/> +" clip-path="url(#pfca057b264)" style="fill: #1f77b4"/> @@ -6669,7 +6669,7 @@ L 163.282375 349.763893 L 150.859369 350.056493 L 138.436364 349.799605 z -" clip-path="url(#p1f874ef36a)" style="fill: #1f77b4"/> +" clip-path="url(#p53c4a3e10e)" style="fill: #1f77b4"/> @@ -6797,7 +6797,7 @@ L 163.282375 355.224923 L 150.859369 355.09084 L 138.436364 355.015479 z -" clip-path="url(#p68931db2c6)" style="fill: #1f77b4"/> +" clip-path="url(#p45e8e170f9)" style="fill: #1f77b4"/> @@ -6925,7 +6925,7 @@ L 163.282375 359.542475 L 150.859369 358.925051 L 138.436364 359.01289 z -" clip-path="url(#p314a4fa0be)" style="fill: #1f77b4"/> +" clip-path="url(#p255b026332)" style="fill: #1f77b4"/> @@ -7053,7 +7053,7 @@ L 163.282375 365.529556 L 150.859369 363.079744 L 138.436364 362.488053 z -" clip-path="url(#p7a7c8a7734)" style="fill: #1f77b4"/> +" clip-path="url(#p059ba131c3)" style="fill: #1f77b4"/> @@ -7181,7 +7181,7 @@ L 163.282375 370.623583 L 150.859369 370.623583 L 138.436364 370.370125 z -" clip-path="url(#pe5225c95d6)" style="fill: #1f77b4"/> +" clip-path="url(#p4d6d4a7411)" style="fill: #1f77b4"/> @@ -7309,7 +7309,7 @@ L 163.282375 375.488923 L 150.859369 375.19077 L 138.436364 375.281553 z -" clip-path="url(#pe6cf8f9895)" style="fill: #1f77b4"/> +" clip-path="url(#p3ea6f48365)" style="fill: #1f77b4"/> @@ -7437,7 +7437,7 @@ L 163.282375 379.611026 L 150.859369 380.074061 L 138.436364 380.201158 z -" clip-path="url(#pc3dcabef4f)" style="fill: #1f77b4"/> +" clip-path="url(#p6651c7d293)" style="fill: #1f77b4"/> @@ -7565,7 +7565,7 @@ L 163.282375 385.864216 L 150.859369 385.86747 L 138.436364 385.874052 z -" clip-path="url(#p1a22f8e4a6)" style="fill: #1f77b4"/> +" clip-path="url(#pcea9fe8bd8)" style="fill: #1f77b4"/> @@ -7693,7 +7693,7 @@ L 163.282375 390.999694 L 150.859369 390.999694 L 138.436364 390.999694 z -" clip-path="url(#p22305e73a0)" style="fill: #1f77b4"/> +" clip-path="url(#pd7ea449ad6)" style="fill: #1f77b4"/> @@ -7821,7 +7821,7 @@ L 163.282375 396.093721 L 150.859369 396.093721 L 138.436364 396.093721 z -" clip-path="url(#p624d444f0f)" style="fill: #1f77b4"/> +" clip-path="url(#p92e32fec67)" style="fill: #1f77b4"/> @@ -7949,7 +7949,7 @@ L 163.282375 399.81562 L 150.859369 399.92333 L 138.436364 397.786498 z -" clip-path="url(#p6cc4bc6346)" style="fill: #1f77b4"/> +" clip-path="url(#p370e76f4e0)" style="fill: #1f77b4"/> @@ -8077,7 +8077,7 @@ L 163.282375 406.039391 L 150.859369 406.159944 L 138.436364 406.214551 z -" clip-path="url(#p6954ad7320)" style="fill: #1f77b4"/> +" clip-path="url(#p4e3fe443b8)" style="fill: #1f77b4"/> @@ -8205,7 +8205,7 @@ L 163.282375 411.222154 L 150.859369 410.951038 L 138.436364 410.760554 z -" clip-path="url(#p54f71c7bca)" style="fill: #1f77b4"/> +" clip-path="url(#p95d5cb959a)" style="fill: #1f77b4"/> @@ -8333,7 +8333,7 @@ L 163.282375 416.469832 L 150.859369 416.469832 L 138.436364 416.469832 z -" clip-path="url(#pc3c7e8ea35)" style="fill: #1f77b4"/> +" clip-path="url(#p1fb40a88f2)" style="fill: #1f77b4"/> @@ -8461,7 +8461,7 @@ L 163.282375 419.059984 L 150.859369 419.011074 L 138.436364 419.329063 z -" clip-path="url(#p172e3ef015)" style="fill: #1f77b4"/> +" clip-path="url(#p51f897b34d)" style="fill: #1f77b4"/> @@ -8589,7 +8589,7 @@ L 163.282375 425.56209 L 150.859369 425.850064 L 138.436364 425.320643 z -" clip-path="url(#p2f4219f82d)" style="fill: #1f77b4"/> +" clip-path="url(#pe07b6450c9)" style="fill: #1f77b4"/> @@ -8717,7 +8717,7 @@ L 163.282375 431.751914 L 150.859369 431.751914 L 138.436364 431.667973 z -" clip-path="url(#p039387faa8)" style="fill: #1f77b4"/> +" clip-path="url(#p24fa652038)" style="fill: #1f77b4"/> @@ -8845,7 +8845,7 @@ L 163.282375 436.682896 L 150.859369 436.789599 L 138.436364 436.845942 z -" clip-path="url(#p6e24c38f01)" style="fill: #1f77b4"/> +" clip-path="url(#p07c5620f56)" style="fill: #1f77b4"/> @@ -8973,7 +8973,7 @@ L 163.282375 439.673099 L 150.859369 439.474353 L 138.436364 440.919594 z -" clip-path="url(#pb72267fbdf)" style="fill: #1f77b4"/> +" clip-path="url(#p4e3fafc268)" style="fill: #1f77b4"/> @@ -9101,7 +9101,7 @@ L 163.282375 447.033997 L 150.859369 447.033997 L 138.436364 447.033997 z -" clip-path="url(#p2151eb46be)" style="fill: #1f77b4"/> +" clip-path="url(#pb2b68905a4)" style="fill: #1f77b4"/> @@ -9229,7 +9229,7 @@ L 163.282375 451.290097 L 150.859369 451.024951 L 138.436364 451.215028 z -" clip-path="url(#p6854fb00b6)" style="fill: #1f77b4"/> +" clip-path="url(#p5ccec6cc11)" style="fill: #1f77b4"/> @@ -9357,7 +9357,7 @@ L 163.282375 455.093982 L 150.859369 453.986369 L 138.436364 455.030861 z -" clip-path="url(#p127aacfc69)" style="fill: #1f77b4"/> +" clip-path="url(#p8bf73fadf1)" style="fill: #1f77b4"/> @@ -9485,7 +9485,7 @@ L 163.282375 461.11904 L 150.859369 461.654235 L 138.436364 459.394492 z -" clip-path="url(#p4d2d0e9a15)" style="fill: #1f77b4"/> +" clip-path="url(#p4fcc7c3d31)" style="fill: #1f77b4"/> @@ -9613,7 +9613,7 @@ L 163.282375 466.609699 L 150.859369 466.303741 L 138.436364 466.723316 z -" clip-path="url(#pb889106f32)" style="fill: #1f77b4"/> +" clip-path="url(#p0b0e55b4e7)" style="fill: #1f77b4"/> @@ -9741,7 +9741,7 @@ L 163.282375 471.903828 L 150.859369 471.858754 L 138.436364 470.901622 z -" clip-path="url(#p056b5ea1d7)" style="fill: #1f77b4"/> +" clip-path="url(#p024f6ce5bc)" style="fill: #1f77b4"/> @@ -9869,7 +9869,7 @@ L 163.282375 477.140786 L 150.859369 476.755216 L 138.436364 477.249316 z -" clip-path="url(#p44a614b5e9)" style="fill: #1f77b4"/> +" clip-path="url(#pba928d6504)" style="fill: #1f77b4"/> @@ -9997,7 +9997,7 @@ L 163.282375 482.311639 L 150.859369 482.69219 L 138.436364 482.305189 z -" clip-path="url(#p8f192c384b)" style="fill: #1f77b4"/> +" clip-path="url(#p59948fa358)" style="fill: #1f77b4"/> @@ -10125,7 +10125,7 @@ L 163.282375 487.697601 L 150.859369 487.296255 L 138.436364 487.65104 z -" clip-path="url(#pd1187d87f8)" style="fill: #1f77b4"/> +" clip-path="url(#p2ec0e239ab)" style="fill: #1f77b4"/> @@ -10253,7 +10253,7 @@ L 163.282375 492.500459 L 150.859369 492.394171 L 138.436364 492.815875 z -" clip-path="url(#p9f69815762)" style="fill: #1f77b4"/> +" clip-path="url(#p162b2678dc)" style="fill: #1f77b4"/> @@ -10381,7 +10381,7 @@ L 163.282375 497.088106 L 150.859369 497.565971 L 138.436364 497.298383 z -" clip-path="url(#pac1a31e28e)" style="fill: #1f77b4"/> +" clip-path="url(#pa01a4e67e1)" style="fill: #1f77b4"/> @@ -10509,7 +10509,7 @@ L 163.282375 501.880392 L 150.859369 502.122913 L 138.436364 502.738834 z -" clip-path="url(#p8ee524bb5f)" style="fill: #1f77b4"/> +" clip-path="url(#p2c5c8ab941)" style="fill: #1f77b4"/> @@ -10637,7 +10637,7 @@ L 163.282375 508.162328 L 150.859369 507.760611 L 138.436364 506.832351 z -" clip-path="url(#p10e718ea87)" style="fill: #1f77b4"/> +" clip-path="url(#p83f171293d)" style="fill: #1f77b4"/> @@ -10765,7 +10765,7 @@ L 163.282375 513.256355 L 150.859369 513.055497 L 138.436364 513.256355 z -" clip-path="url(#p9d9e96a237)" style="fill: #1f77b4"/> +" clip-path="url(#p79751c21e1)" style="fill: #1f77b4"/> @@ -10893,7 +10893,7 @@ L 163.282375 517.962884 L 150.859369 518.171842 L 138.436364 518.12872 z -" clip-path="url(#p101e5d8bcc)" style="fill: #1f77b4"/> +" clip-path="url(#p7d0dff19e1)" style="fill: #1f77b4"/> @@ -11021,7 +11021,7 @@ L 163.282375 523.117458 L 150.859369 523.343981 L 138.436364 523.361287 z -" clip-path="url(#p8d81371afa)" style="fill: #1f77b4"/> +" clip-path="url(#p057c37fd19)" style="fill: #1f77b4"/> @@ -11149,7 +11149,7 @@ L 163.282375 528.538438 L 150.859369 527.254263 L 138.436364 525.349765 z -" clip-path="url(#p912f483b93)" style="fill: #1f77b4"/> +" clip-path="url(#p60895656ae)" style="fill: #1f77b4"/> @@ -11277,7 +11277,7 @@ L 163.282375 533.513634 L 150.859369 533.562782 L 138.436364 533.55831 z -" clip-path="url(#pa5c2229cd2)" style="fill: #1f77b4"/> +" clip-path="url(#p1730b0f3fb)" style="fill: #1f77b4"/> @@ -11405,7 +11405,7 @@ L 163.282375 538.593772 L 150.859369 538.634766 L 138.436364 538.675879 z -" clip-path="url(#pe1054f0950)" style="fill: #1f77b4"/> +" clip-path="url(#pf9274429ea)" style="fill: #1f77b4"/> @@ -11533,7 +11533,7 @@ L 163.282375 542.357274 L 150.859369 542.523997 L 138.436364 542.210854 z -" clip-path="url(#pe5aa5b3bd6)" style="fill: #1f77b4"/> +" clip-path="url(#pee3bf41c52)" style="fill: #1f77b4"/> @@ -11661,7 +11661,7 @@ L 163.282375 548.801991 L 150.859369 548.914548 L 138.436364 548.914548 z -" clip-path="url(#pd59997137c)" style="fill: #1f77b4"/> +" clip-path="url(#pa3697e79ca)" style="fill: #1f77b4"/> @@ -11789,7 +11789,7 @@ L 163.282375 553.751302 L 150.859369 553.652958 L 138.436364 553.861406 z -" clip-path="url(#pc8ab45e284)" style="fill: #1f77b4"/> +" clip-path="url(#pcca8ab1a26)" style="fill: #1f77b4"/> @@ -11917,7 +11917,7 @@ L 163.282375 558.920692 L 150.859369 559.102603 L 138.436364 559.102603 z -" clip-path="url(#p7e893c518d)" style="fill: #1f77b4"/> +" clip-path="url(#p61ac720fce)" style="fill: #1f77b4"/> @@ -12045,7 +12045,7 @@ L 163.282375 563.446248 L 150.859369 563.966138 L 138.436364 564.005856 z -" clip-path="url(#pfcccc66c32)" style="fill: #1f77b4"/> +" clip-path="url(#pf084b22e1e)" style="fill: #1f77b4"/> @@ -12173,7 +12173,7 @@ L 163.282375 568.679235 L 150.859369 568.829672 L 138.436364 569.036291 z -" clip-path="url(#pa8e44591d6)" style="fill: #1f77b4"/> +" clip-path="url(#pf1dc8b5f08)" style="fill: #1f77b4"/> @@ -12301,7 +12301,7 @@ L 163.282375 572.717169 L 150.859369 571.772432 L 138.436364 571.077914 z -" clip-path="url(#p5903aa2a41)" style="fill: #1f77b4"/> +" clip-path="url(#p4422ae0908)" style="fill: #1f77b4"/> @@ -12429,7 +12429,7 @@ L 163.282375 579.478714 L 150.859369 579.478714 L 138.436364 579.478714 z -" clip-path="url(#pb967ced3b4)" style="fill: #1f77b4"/> +" clip-path="url(#pd123402b60)" style="fill: #1f77b4"/> @@ -12557,7 +12557,7 @@ L 163.282375 584.572741 L 150.859369 584.572741 L 138.436364 584.572741 z -" clip-path="url(#p055bcd36e5)" style="fill: #1f77b4"/> +" clip-path="url(#p53cef94cf7)" style="fill: #1f77b4"/> @@ -12685,7 +12685,7 @@ L 163.282375 589.123635 L 150.859369 589.499936 L 138.436364 588.976344 z -" clip-path="url(#pda9e973318)" style="fill: #1f77b4"/> +" clip-path="url(#p9dcac5b70a)" style="fill: #1f77b4"/> @@ -12813,7 +12813,7 @@ L 163.282375 593.97332 L 150.859369 593.644395 L 138.436364 594.229481 z -" clip-path="url(#pf5cc905880)" style="fill: #1f77b4"/> +" clip-path="url(#p448bdf4fa7)" style="fill: #1f77b4"/> @@ -12941,7 +12941,7 @@ L 163.282375 599.582236 L 150.859369 599.491993 L 138.436364 599.346609 z -" clip-path="url(#p3a80d86090)" style="fill: #1f77b4"/> +" clip-path="url(#pa1fec78940)" style="fill: #1f77b4"/> @@ -13069,7 +13069,7 @@ L 163.282375 604.736839 L 150.859369 604.948851 L 138.436364 604.948851 z -" clip-path="url(#p874cdb5ffd)" style="fill: #1f77b4"/> +" clip-path="url(#p393569d514)" style="fill: #1f77b4"/> @@ -13197,7 +13197,7 @@ L 163.282375 610.042879 L 150.859369 610.042879 L 138.436364 610.015928 z -" clip-path="url(#pd31b1ae334)" style="fill: #1f77b4"/> +" clip-path="url(#p21e8b5002f)" style="fill: #1f77b4"/> @@ -13325,7 +13325,7 @@ L 163.282375 613.569142 L 150.859369 613.884836 L 138.436364 614.818039 z -" clip-path="url(#pf520ee413d)" style="fill: #1f77b4"/> +" clip-path="url(#pca286fe48b)" style="fill: #1f77b4"/> @@ -13453,7 +13453,7 @@ L 163.282375 619.673507 L 150.859369 617.919418 L 138.436364 618.105152 z -" clip-path="url(#pf89c1d9f7b)" style="fill: #1f77b4"/> +" clip-path="url(#pddf26d57de)" style="fill: #1f77b4"/> @@ -13581,7 +13581,7 @@ L 163.282375 625.243387 L 150.859369 625.24979 L 138.436364 625.044981 z -" clip-path="url(#pd725f28ee7)" style="fill: #1f77b4"/> +" clip-path="url(#p5d181d8e8b)" style="fill: #1f77b4"/> @@ -13709,7 +13709,7 @@ L 163.282375 630.418989 L 150.859369 630.418989 L 138.436364 630.418989 z -" clip-path="url(#p26e4c95d86)" style="fill: #1f77b4"/> +" clip-path="url(#pdf799b9b4e)" style="fill: #1f77b4"/> @@ -13837,7 +13837,7 @@ L 163.282375 635.513017 L 150.859369 635.384599 L 138.436364 635.513017 z -" clip-path="url(#p064f6d41b2)" style="fill: #1f77b4"/> +" clip-path="url(#pec18780e6a)" style="fill: #1f77b4"/> @@ -13965,18 +13965,18 @@ L 163.282375 639.998942 L 150.859369 639.486309 L 138.436364 638.635865 z -" clip-path="url(#p911065e36b)" style="fill: #1f77b4"/> +" clip-path="url(#p7504786eb1)" style="fill: #1f77b4"/> - - + @@ -14012,7 +14012,7 @@ z - + @@ -14052,7 +14052,7 @@ z - + @@ -14087,7 +14087,7 @@ z - + @@ -14133,7 +14133,7 @@ z - + @@ -14188,7 +14188,7 @@ z - + @@ -14219,7 +14219,7 @@ z - + @@ -14234,7 +14234,7 @@ z - + @@ -14249,7 +14249,7 @@ z - + @@ -14500,331 +14500,331 @@ L 777.6 640.8 - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg b/docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg index 97755fe2..4d816a86 100644 --- a/docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg +++ b/docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:11:24.024905 + 2024-11-21T17:27:10.094376 image/svg+xml @@ -41,12 +41,12 @@ z - - + @@ -82,7 +82,7 @@ z - + @@ -111,7 +111,7 @@ z - + @@ -150,7 +150,7 @@ z - + @@ -197,7 +197,7 @@ z - + @@ -231,7 +231,7 @@ z - + @@ -271,7 +271,7 @@ z - + @@ -590,12 +590,12 @@ z - - + @@ -619,7 +619,7 @@ z - + @@ -634,7 +634,7 @@ z - + @@ -649,7 +649,7 @@ z - + @@ -664,7 +664,7 @@ z - + @@ -679,7 +679,7 @@ z - + @@ -694,7 +694,7 @@ z - + @@ -709,7 +709,7 @@ z - + @@ -736,7 +736,7 @@ z - + @@ -1003,7 +1003,7 @@ L 390.302704 275.526196 L 393.030894 278.943558 L 395.759083 277.90626 L 398.487273 270.043746 -" clip-path="url(#pce426ebda3)" style="fill: none; stroke: #ff0000; stroke-width: 2; stroke-linecap: square"/> +" clip-path="url(#p1a3437ee01)" style="fill: none; stroke: #ff0000; stroke-width: 2; stroke-linecap: square"/> +" clip-path="url(#p1a3437ee01)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1a3437ee01)" style="fill: none; stroke: #008000; stroke-opacity: 0.5; stroke-width: 1.5; stroke-linecap: square"/> + diff --git a/docs/how_to_guide/plot_02_glm_demo.md b/docs/how_to_guide/plot_02_glm_demo.md index bdad8fc1..627410a7 100644 --- a/docs/how_to_guide/plot_02_glm_demo.md +++ b/docs/how_to_guide/plot_02_glm_demo.md @@ -437,6 +437,8 @@ plt.legend() ```{code-cell} ipython3 :tags: [hide-input] +plt.rcParams['svg.hashsalt'] = None + # save image for thumbnail from pathlib import Path From be11da1c3c5e47139e77117a96aef134b5174247 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 17:40:00 -0500 Subject: [PATCH 071/107] clear date --- .../how_to_guide/plot_02_glm_demo.svg | 138 +++++++++--------- docs/background/plot_01_1D_basis_function.md | 2 +- docs/background/plot_02_ND_basis_function.md | 2 +- docs/background/plot_03_1D_convolution.md | 2 +- docs/how_to_guide/plot_02_glm_demo.md | 4 +- docs/how_to_guide/plot_03_population_glm.md | 2 +- docs/how_to_guide/plot_04_batch_glm.md | 2 +- .../plot_05_sklearn_pipeline_cv_demo.md | 2 +- docs/how_to_guide/plot_06_glm_pytree.md | 2 +- docs/tutorials/plot_01_current_injection.md | 2 +- docs/tutorials/plot_02_head_direction.md | 2 +- docs/tutorials/plot_03_grid_cells.md | 2 +- docs/tutorials/plot_04_v1_cells.md | 2 +- docs/tutorials/plot_05_place_cells.md | 2 +- docs/tutorials/plot_06_calcium_imaging.md | 2 +- 15 files changed, 83 insertions(+), 85 deletions(-) diff --git a/docs/assets/thumbnails/how_to_guide/plot_02_glm_demo.svg b/docs/assets/thumbnails/how_to_guide/plot_02_glm_demo.svg index 07e8fe75..f0733a75 100644 --- a/docs/assets/thumbnails/how_to_guide/plot_02_glm_demo.svg +++ b/docs/assets/thumbnails/how_to_guide/plot_02_glm_demo.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:28:01.655472 + image/svg+xml @@ -43,18 +43,18 @@ L 236.32249 307.584 L 236.32249 24.486128 L 138.828632 24.486128 z -" clip-path="url(#p32270c59a3)" style="fill: #808080; opacity: 0.2; stroke: #808080; stroke-linejoin: miter"/> +" clip-path="url(#pcd817e88c7)" style="fill: #808080; opacity: 0.2; stroke: #808080; stroke-linejoin: miter"/> - - + @@ -90,7 +90,7 @@ z - + @@ -131,7 +131,7 @@ z - + @@ -167,7 +167,7 @@ z - + @@ -214,7 +214,7 @@ z - + @@ -270,7 +270,7 @@ z - + @@ -304,12 +304,12 @@ z - - + @@ -334,7 +334,7 @@ z - + @@ -350,7 +350,7 @@ z - + @@ -366,7 +366,7 @@ z - + @@ -382,7 +382,7 @@ z - + @@ -398,7 +398,7 @@ z - + @@ -414,7 +414,7 @@ z - + @@ -1021,7 +1021,7 @@ L 396.862375 263.006827 L 397.512334 260.237355 L 398.487273 254.514111 L 398.487273 254.514111 -" clip-path="url(#p32270c59a3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5"/> +" clip-path="url(#pcd817e88c7)" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linecap: square"/> + diff --git a/docs/background/plot_01_1D_basis_function.md b/docs/background/plot_01_1D_basis_function.md index 05edebe4..c108a5fb 100644 --- a/docs/background/plot_01_1D_basis_function.md +++ b/docs/background/plot_01_1D_basis_function.md @@ -97,7 +97,7 @@ from pathlib import Path path = Path("../assets/thumbnails/background") if path.exists(): - fig.savefig(path / "plot_01_1D_basis_function.svg") + fig.savefig(path / "plot_01_1D_basis_function.svg", metadata={"Date":""}) ``` ## Setting the basis support diff --git a/docs/background/plot_02_ND_basis_function.md b/docs/background/plot_02_ND_basis_function.md index 84bbcdeb..f35d8ddb 100644 --- a/docs/background/plot_02_ND_basis_function.md +++ b/docs/background/plot_02_ND_basis_function.md @@ -301,7 +301,7 @@ from pathlib import Path path = Path("../assets/thumbnails/background") if path.exists(): - fig.savefig(path / "plot_02_ND_basis_function.svg") + fig.savefig(path / "plot_02_ND_basis_function.svg", metadata={"Date":""}) ``` :::{info} diff --git a/docs/background/plot_03_1D_convolution.md b/docs/background/plot_03_1D_convolution.md index 04faf528..4092dfee 100644 --- a/docs/background/plot_03_1D_convolution.md +++ b/docs/background/plot_03_1D_convolution.md @@ -172,7 +172,7 @@ from pathlib import Path path = Path("../assets/thumbnails/background") if path.exists(): - fig.savefig(path / "plot_03_1D_convolution.svg") + fig.savefig(path / "plot_03_1D_convolution.svg", metadata={"Date":""}) ``` ## Convolve using [`Basis.compute_features`](nemos.basis.Basis.compute_features) diff --git a/docs/how_to_guide/plot_02_glm_demo.md b/docs/how_to_guide/plot_02_glm_demo.md index 627410a7..67084c88 100644 --- a/docs/how_to_guide/plot_02_glm_demo.md +++ b/docs/how_to_guide/plot_02_glm_demo.md @@ -437,14 +437,12 @@ plt.legend() ```{code-cell} ipython3 :tags: [hide-input] -plt.rcParams['svg.hashsalt'] = None - # save image for thumbnail from pathlib import Path path = Path("../assets/thumbnails/how_to_guide") if path.exists(): - fig.savefig(path / "plot_02_glm_demo.svg") + fig.savefig(path / "plot_02_glm_demo.svg", metadata={"Date":""}) ``` diff --git a/docs/how_to_guide/plot_03_population_glm.md b/docs/how_to_guide/plot_03_population_glm.md index 1239fed8..a4fc9f23 100644 --- a/docs/how_to_guide/plot_03_population_glm.md +++ b/docs/how_to_guide/plot_03_population_glm.md @@ -223,7 +223,7 @@ from pathlib import Path path = Path("../assets/thumbnails/how_to_guide") if path.exists(): - fig.savefig(path / "plot_03_population_glm.svg") + fig.savefig(path / "plot_03_population_glm.svg", metadata={"Date":""}) ``` ## FeaturePytree diff --git a/docs/how_to_guide/plot_04_batch_glm.md b/docs/how_to_guide/plot_04_batch_glm.md index 63342acc..d2ecf872 100644 --- a/docs/how_to_guide/plot_04_batch_glm.md +++ b/docs/how_to_guide/plot_04_batch_glm.md @@ -201,7 +201,7 @@ from pathlib import Path path = Path("../assets/thumbnails/how_to_guide") if path.exists(): - fig.savefig(path / "plot_04_batch_glm.svg") + fig.savefig(path / "plot_04_batch_glm.svg", metadata={"Date":""}) ``` We can see that the log-likelihood is increasing but did not reach plateau yet. diff --git a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md index 170ab68b..2b0004ca 100644 --- a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md +++ b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md @@ -424,7 +424,7 @@ from pathlib import Path path = Path("../assets/thumbnails/how_to_guide") if path.exists(): - fig.savefig(path / "plot_05_sklearn_pipeline_cv_demo.svg") + fig.savefig(path / "plot_05_sklearn_pipeline_cv_demo.svg", metadata={"Date":""}) ``` :rocket::rocket::rocket: **Success!** :rocket::rocket::rocket: diff --git a/docs/how_to_guide/plot_06_glm_pytree.md b/docs/how_to_guide/plot_06_glm_pytree.md index 58146377..e2511bd9 100644 --- a/docs/how_to_guide/plot_06_glm_pytree.md +++ b/docs/how_to_guide/plot_06_glm_pytree.md @@ -254,7 +254,7 @@ from pathlib import Path path = Path("../assets/thumbnails/how_to_guide") if path.exists(): - fig.savefig(path / "plot_06_glm_pytree.svg") + fig.savefig(path / "plot_06_glm_pytree.svg", metadata={"Date":""}) ``` diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md index 6f82cbd9..ff4281f1 100644 --- a/docs/tutorials/plot_01_current_injection.md +++ b/docs/tutorials/plot_01_current_injection.md @@ -627,7 +627,7 @@ from pathlib import Path path = Path("../assets/thumbnails/tutorials") if path.exists(): - fig.savefig(path / "plot_01_current_injection.svg") + fig.savefig(path / "plot_01_current_injection.svg", metadata={"Date":""}) ``` What do we see above? Note that the y-axes in the final row are different for diff --git a/docs/tutorials/plot_02_head_direction.md b/docs/tutorials/plot_02_head_direction.md index b6918bde..43dd9262 100644 --- a/docs/tutorials/plot_02_head_direction.md +++ b/docs/tutorials/plot_02_head_direction.md @@ -708,5 +708,5 @@ from pathlib import Path path = Path("../assets/thumbnails/tutorials") if path.exists(): - fig.savefig(path / "plot_02_head_direction.svg") + fig.savefig(path / "plot_02_head_direction.svg", metadata={"Date":""}) ``` \ No newline at end of file diff --git a/docs/tutorials/plot_03_grid_cells.md b/docs/tutorials/plot_03_grid_cells.md index 55e9dfee..d7d5d6f8 100644 --- a/docs/tutorials/plot_03_grid_cells.md +++ b/docs/tutorials/plot_03_grid_cells.md @@ -337,5 +337,5 @@ from pathlib import Path path = Path("../assets/thumbnails/tutorials") if path.exists(): - fig.savefig(path / "plot_03_grid_cells.svg") + fig.savefig(path / "plot_03_grid_cells.svg", metadata={"Date":""}) ``` \ No newline at end of file diff --git a/docs/tutorials/plot_04_v1_cells.md b/docs/tutorials/plot_04_v1_cells.md index d413a4be..60985584 100644 --- a/docs/tutorials/plot_04_v1_cells.md +++ b/docs/tutorials/plot_04_v1_cells.md @@ -240,7 +240,7 @@ from pathlib import Path path = Path("../assets/thumbnails/tutorials") if path.exists(): - fig.savefig(path / "plot_04_v1_cells.svg") + fig.savefig(path / "plot_04_v1_cells.svg", metadata={"Date":""}) ``` This receptive field gives us the spatial part of the linear response: it diff --git a/docs/tutorials/plot_05_place_cells.md b/docs/tutorials/plot_05_place_cells.md index a8e80020..b12435e8 100644 --- a/docs/tutorials/plot_05_place_cells.md +++ b/docs/tutorials/plot_05_place_cells.md @@ -152,7 +152,7 @@ from pathlib import Path path = Path("../assets/thumbnails/tutorials") if path.exists(): - fig.savefig(path / "plot_05_place_cells.svg") + fig.savefig(path / "plot_05_place_cells.svg", metadata={"Date":""}) ``` ## Phase precession diff --git a/docs/tutorials/plot_06_calcium_imaging.md b/docs/tutorials/plot_06_calcium_imaging.md index c43091e3..ef688398 100644 --- a/docs/tutorials/plot_06_calcium_imaging.md +++ b/docs/tutorials/plot_06_calcium_imaging.md @@ -364,7 +364,7 @@ from pathlib import Path path = Path("../assets/thumbnails/tutorials") if path.exists(): - fig.savefig(path / "plot_06_calcium_imaging.svg") + fig.savefig(path / "plot_06_calcium_imaging.svg", metadata={"Date":""}) ``` From eef2b30838e6f0565d6a1beac6d5b8a24adef84f Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 17:42:11 -0500 Subject: [PATCH 072/107] clear date --- .../background/plot_01_1D_basis_function.svg | 52 +- .../background/plot_02_ND_basis_function.svg | 398 +-- .../background/plot_03_1D_convolution.svg | 692 ++--- .../how_to_guide/plot_03_population_glm.svg | 78 +- .../how_to_guide/plot_04_batch_glm.svg | 34 +- .../plot_05_sklearn_pipeline_cv_demo.svg | 2380 ++++++++--------- .../how_to_guide/plot_06_glm_pytree.svg | 236 +- 7 files changed, 1923 insertions(+), 1947 deletions(-) diff --git a/docs/assets/thumbnails/background/plot_01_1D_basis_function.svg b/docs/assets/thumbnails/background/plot_01_1D_basis_function.svg index d37e76f0..fe983fea 100644 --- a/docs/assets/thumbnails/background/plot_01_1D_basis_function.svg +++ b/docs/assets/thumbnails/background/plot_01_1D_basis_function.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:23:22.546960 + image/svg+xml @@ -41,12 +41,12 @@ z - - + @@ -82,7 +82,7 @@ z - + @@ -123,7 +123,7 @@ z - + @@ -159,7 +159,7 @@ z - + @@ -206,7 +206,7 @@ z - + @@ -262,7 +262,7 @@ z - + @@ -296,12 +296,12 @@ z - - + @@ -325,7 +325,7 @@ z - + @@ -340,7 +340,7 @@ z - + @@ -355,7 +355,7 @@ z - + @@ -370,7 +370,7 @@ z - + @@ -385,7 +385,7 @@ z - + @@ -428,7 +428,7 @@ L 117.336436 295.430344 L 120.258327 295.488 L 398.487273 295.488 L 398.487273 295.488 -" clip-path="url(#p5458b38fce)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p50a1027306)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p50a1027306)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p50a1027306)" style="fill: none; stroke: #2ca02c; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p50a1027306)" style="fill: none; stroke: #d62728; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p50a1027306)" style="fill: none; stroke: #9467bd; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p50a1027306)" style="fill: none; stroke: #8c564b; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p50a1027306)" style="fill: none; stroke: #e377c2; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p50a1027306)" style="fill: none; stroke: #7f7f7f; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p50a1027306)" style="fill: none; stroke: #bcbd22; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p50a1027306)" style="fill: none; stroke: #17becf; stroke-width: 1.5; stroke-linecap: square"/> + diff --git a/docs/assets/thumbnails/background/plot_02_ND_basis_function.svg b/docs/assets/thumbnails/background/plot_02_ND_basis_function.svg index ce171a58..cfddbc34 100644 --- a/docs/assets/thumbnails/background/plot_02_ND_basis_function.svg +++ b/docs/assets/thumbnails/background/plot_02_ND_basis_function.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:23:29.898877 + image/svg+xml @@ -41,12 +41,12 @@ z - - + @@ -92,7 +92,7 @@ z - + @@ -159,7 +159,7 @@ z - + @@ -175,7 +175,7 @@ z - + @@ -203,7 +203,7 @@ z - + @@ -237,12 +237,12 @@ z - - + @@ -255,7 +255,7 @@ L -3.5 0 - + @@ -269,7 +269,7 @@ L -3.5 0 - + @@ -317,7 +317,7 @@ L 47.556612 105.460908 L 47.971858 105.561818 L 175.591026 105.561818 L 175.591026 105.561818 -" clip-path="url(#p72c0ed5623)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa702f83824)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa702f83824)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa702f83824)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa702f83824)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa702f83824)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa702f83824)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa702f83824)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa702f83824)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa702f83824)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa702f83824)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa702f83824)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa702f83824)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa702f83824)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa702f83824)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa702f83824)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa702f83824)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> - + @@ -921,7 +921,7 @@ z - + @@ -937,7 +937,7 @@ z - + @@ -953,7 +953,7 @@ z - + @@ -969,7 +969,7 @@ z - + @@ -987,7 +987,7 @@ z - + @@ -1002,7 +1002,7 @@ z - + @@ -1017,7 +1017,7 @@ z - + @@ -1039,7 +1039,7 @@ L 230.460819 105.210754 L 230.599234 105.561818 L 366.938584 105.561818 L 366.938584 105.561818 -" clip-path="url(#p2d5a34994d)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5c241b0aaf)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5c241b0aaf)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5c241b0aaf)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5c241b0aaf)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5c241b0aaf)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5c241b0aaf)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5c241b0aaf)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5c241b0aaf)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5c241b0aaf)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5c241b0aaf)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5c241b0aaf)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5c241b0aaf)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5c241b0aaf)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5c241b0aaf)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5c241b0aaf)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p943e9db96e)" style="fill: #eaf3fb"/> +" clip-path="url(#p943e9db96e)" style="fill: #d2e3f3"/> +" clip-path="url(#p943e9db96e)" style="fill: #b2d2e8"/> +" clip-path="url(#p943e9db96e)" style="fill: #84bcdb"/> +" clip-path="url(#p943e9db96e)" style="fill: #56a0ce"/> +" clip-path="url(#p943e9db96e)" style="fill: #3181bd"/> +" clip-path="url(#p943e9db96e)" style="fill: #1460a8"/> +" clip-path="url(#p943e9db96e)" style="fill: #084082"/> - + @@ -2506,7 +2506,7 @@ z - + @@ -2521,7 +2521,7 @@ z - + @@ -2659,7 +2659,7 @@ z - + @@ -2675,7 +2675,7 @@ z - + @@ -2691,7 +2691,7 @@ z - + @@ -2707,7 +2707,7 @@ z - + @@ -2723,7 +2723,7 @@ z - + @@ -2873,7 +2873,7 @@ z - + @@ -2889,7 +2889,7 @@ z - + @@ -2905,7 +2905,7 @@ z - + @@ -2921,7 +2921,7 @@ z - + @@ -2937,7 +2937,7 @@ z - + @@ -2955,7 +2955,7 @@ z - + @@ -2968,7 +2968,7 @@ z - + @@ -2982,7 +2982,7 @@ z - + @@ -3009,7 +3009,7 @@ L 47.556612 245.860908 L 47.971858 245.961818 L 175.591026 245.961818 L 175.591026 245.961818 -" clip-path="url(#pe5f2e0e638)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3550036e94)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3550036e94)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3550036e94)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3550036e94)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3550036e94)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3550036e94)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3550036e94)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3550036e94)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3550036e94)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3550036e94)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3550036e94)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3550036e94)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3550036e94)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3550036e94)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3550036e94)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3550036e94)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> - + @@ -3552,7 +3552,7 @@ z - + @@ -3568,7 +3568,7 @@ z - + @@ -3584,7 +3584,7 @@ z - + @@ -3600,7 +3600,7 @@ z - + @@ -3618,7 +3618,7 @@ z - + @@ -3633,7 +3633,7 @@ z - + @@ -3648,7 +3648,7 @@ z - + @@ -3670,7 +3670,7 @@ L 230.460819 245.610754 L 230.599234 245.961818 L 366.938584 245.961818 L 366.938584 245.961818 -" clip-path="url(#p862d7c8e0e)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd3c5d664dd)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd3c5d664dd)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd3c5d664dd)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd3c5d664dd)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd3c5d664dd)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd3c5d664dd)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd3c5d664dd)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd3c5d664dd)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd3c5d664dd)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd3c5d664dd)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd3c5d664dd)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd3c5d664dd)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd3c5d664dd)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd3c5d664dd)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd3c5d664dd)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbfe46aa374)" style="fill: #e9f2fa"/> +" clip-path="url(#pbfe46aa374)" style="fill: #cde0f1"/> +" clip-path="url(#pbfe46aa374)" style="fill: #a4cce3"/> +" clip-path="url(#pbfe46aa374)" style="fill: #6aaed6"/> +" clip-path="url(#pbfe46aa374)" style="fill: #3d8dc4"/> +" clip-path="url(#pbfe46aa374)" style="fill: #1967ad"/> +" clip-path="url(#pbfe46aa374)" style="fill: #084387"/> - + @@ -5420,7 +5420,7 @@ z - + @@ -5435,7 +5435,7 @@ z - + @@ -5464,7 +5464,7 @@ z - + @@ -5480,7 +5480,7 @@ z - + @@ -5496,7 +5496,7 @@ z - + @@ -5512,7 +5512,7 @@ z - + @@ -5528,7 +5528,7 @@ z - + @@ -5613,7 +5613,7 @@ z - + @@ -5629,7 +5629,7 @@ z - + @@ -5645,7 +5645,7 @@ z - + @@ -5661,7 +5661,7 @@ z - + @@ -5677,7 +5677,7 @@ z - + @@ -5707,7 +5707,7 @@ z - + @@ -5720,7 +5720,7 @@ z - + @@ -5734,7 +5734,7 @@ z - + @@ -5761,7 +5761,7 @@ L 47.556612 386.260908 L 47.971858 386.361818 L 175.591026 386.361818 L 175.591026 386.361818 -" clip-path="url(#p7ee9d45014)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8362b02d61)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8362b02d61)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8362b02d61)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8362b02d61)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8362b02d61)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8362b02d61)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8362b02d61)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8362b02d61)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8362b02d61)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8362b02d61)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8362b02d61)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8362b02d61)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8362b02d61)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8362b02d61)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8362b02d61)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8362b02d61)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> - + @@ -6302,7 +6302,7 @@ z - + @@ -6318,7 +6318,7 @@ z - + @@ -6334,7 +6334,7 @@ z - + @@ -6350,7 +6350,7 @@ z - + @@ -6380,7 +6380,7 @@ z - + @@ -6395,7 +6395,7 @@ z - + @@ -6410,7 +6410,7 @@ z - + @@ -6432,7 +6432,7 @@ L 230.460819 386.010754 L 230.599234 386.361818 L 366.938584 386.361818 L 366.938584 386.361818 -" clip-path="url(#p283a51e257)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10f13f13f5)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10f13f13f5)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10f13f13f5)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10f13f13f5)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10f13f13f5)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10f13f13f5)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10f13f13f5)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10f13f13f5)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10f13f13f5)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10f13f13f5)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10f13f13f5)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10f13f13f5)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10f13f13f5)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10f13f13f5)" style="fill: none; stroke: #808080; stroke-opacity: 0.3; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10f13f13f5)" style="fill: none; stroke: #0000ff; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p03a5dbdb08)" style="fill: #e9f2fa"/> +" clip-path="url(#p03a5dbdb08)" style="fill: #cde0f1"/> +" clip-path="url(#p03a5dbdb08)" style="fill: #a4cce3"/> +" clip-path="url(#p03a5dbdb08)" style="fill: #6aaed6"/> +" clip-path="url(#p03a5dbdb08)" style="fill: #3d8dc4"/> +" clip-path="url(#p03a5dbdb08)" style="fill: #1967ad"/> +" clip-path="url(#p03a5dbdb08)" style="fill: #084387"/> - + @@ -8403,7 +8403,7 @@ z - + @@ -8418,7 +8418,7 @@ z - + @@ -8447,7 +8447,7 @@ z - + @@ -8463,7 +8463,7 @@ z - + @@ -8479,7 +8479,7 @@ z - + @@ -8495,7 +8495,7 @@ z - + @@ -8511,7 +8511,7 @@ z - + @@ -8587,31 +8587,31 @@ L 529.607558 309.12 - + - + - + - + - + - + - + - + - + diff --git a/docs/assets/thumbnails/background/plot_03_1D_convolution.svg b/docs/assets/thumbnails/background/plot_03_1D_convolution.svg index f57c7f32..cde68ec9 100644 --- a/docs/assets/thumbnails/background/plot_03_1D_convolution.svg +++ b/docs/assets/thumbnails/background/plot_03_1D_convolution.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:23:36.350383 + image/svg+xml @@ -43,18 +43,18 @@ L 97.982668 83.350909 L 97.982668 29.569091 L 63.579545 29.569091 z -" clip-path="url(#pd40d1c7e12)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> +" clip-path="url(#p7d397bdb75)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> - - + @@ -90,7 +90,7 @@ z - + @@ -130,7 +130,7 @@ z - + @@ -165,7 +165,7 @@ z - + @@ -211,7 +211,7 @@ z - + @@ -266,7 +266,7 @@ z - + @@ -299,12 +299,12 @@ z - - + @@ -361,7 +361,7 @@ z - + @@ -376,7 +376,7 @@ z - + @@ -519,304 +519,304 @@ z +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7d397bdb75)" style="fill: none; stroke: #2ca02c; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe2d75f296e)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> - + @@ -1291,7 +1291,7 @@ z - + @@ -1305,7 +1305,7 @@ z - + @@ -1319,7 +1319,7 @@ z - + @@ -1333,7 +1333,7 @@ z - + @@ -1347,7 +1347,7 @@ z - + @@ -1364,7 +1364,7 @@ z - + @@ -1380,7 +1380,7 @@ z - + @@ -1395,7 +1395,7 @@ z - + @@ -1450,304 +1450,304 @@ z +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe2d75f296e)" style="fill: none; stroke: #2ca02c; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pce65fd8a53)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> +" clip-path="url(#pce65fd8a53)" style="fill: #808080; opacity: 0.3; stroke: #808080; stroke-linejoin: miter"/> - + @@ -2091,7 +2091,7 @@ z - + @@ -2105,7 +2105,7 @@ z - + @@ -2119,7 +2119,7 @@ z - + @@ -2133,7 +2133,7 @@ z - + @@ -2147,7 +2147,7 @@ z - + @@ -2164,7 +2164,7 @@ z - + @@ -2180,7 +2180,7 @@ z - + @@ -2195,7 +2195,7 @@ z - + @@ -2223,304 +2223,304 @@ z +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #000000; stroke-width: 1.5"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pce65fd8a53)" style="fill: none; stroke: #2ca02c; stroke-width: 1.5; stroke-linecap: square"/> + - + - + diff --git a/docs/assets/thumbnails/how_to_guide/plot_03_population_glm.svg b/docs/assets/thumbnails/how_to_guide/plot_03_population_glm.svg index ec8d60bc..1f4e1ce0 100644 --- a/docs/assets/thumbnails/how_to_guide/plot_03_population_glm.svg +++ b/docs/assets/thumbnails/how_to_guide/plot_03_population_glm.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:24:02.443975 + image/svg+xml @@ -43,7 +43,7 @@ L 72.543957 188.12 L 72.543957 65.863003 L 55.123636 65.863003 z -" clip-path="url(#p169d812c27)" style="fill: #1f77b4"/> +" clip-path="url(#p49591714f8)" style="fill: #1f77b4"/> +" clip-path="url(#p49591714f8)" style="fill: #1f77b4"/> +" clip-path="url(#p49591714f8)" style="fill: #ff7f0e"/> +" clip-path="url(#p49591714f8)" style="fill: #ff7f0e"/> +" clip-path="url(#p49591714f8)" style="fill: #2ca02c"/> +" clip-path="url(#p49591714f8)" style="fill: #2ca02c"/> - - + @@ -278,7 +278,7 @@ z - + @@ -317,12 +317,12 @@ z - - + @@ -346,7 +346,7 @@ z - + @@ -361,7 +361,7 @@ z - + @@ -402,7 +402,7 @@ z - + @@ -451,7 +451,7 @@ z - + @@ -487,7 +487,7 @@ z - + @@ -529,7 +529,7 @@ z - + @@ -576,7 +576,7 @@ z - + @@ -603,7 +603,7 @@ z - + @@ -798,7 +798,7 @@ L 283.143957 188.12 L 283.143957 134.233231 L 265.723636 134.233231 z -" clip-path="url(#p6aa75607ec)" style="fill: #1f77b4"/> +" clip-path="url(#pc995242ff0)" style="fill: #1f77b4"/> +" clip-path="url(#pc995242ff0)" style="fill: #1f77b4"/> +" clip-path="url(#pc995242ff0)" style="fill: #ff7f0e"/> +" clip-path="url(#pc995242ff0)" style="fill: #ff7f0e"/> +" clip-path="url(#pc995242ff0)" style="fill: #2ca02c"/> +" clip-path="url(#pc995242ff0)" style="fill: #2ca02c"/> - + @@ -865,7 +865,7 @@ z - + @@ -888,7 +888,7 @@ z - + @@ -903,7 +903,7 @@ z - + @@ -918,7 +918,7 @@ z - + @@ -933,7 +933,7 @@ z - + @@ -948,7 +948,7 @@ z - + @@ -963,7 +963,7 @@ z - + @@ -978,7 +978,7 @@ z - + @@ -993,7 +993,7 @@ z - + @@ -1008,7 +1008,7 @@ z - + @@ -1314,10 +1314,10 @@ z - + - + diff --git a/docs/assets/thumbnails/how_to_guide/plot_04_batch_glm.svg b/docs/assets/thumbnails/how_to_guide/plot_04_batch_glm.svg index 301b3979..1dc2c74b 100644 --- a/docs/assets/thumbnails/how_to_guide/plot_04_batch_glm.svg +++ b/docs/assets/thumbnails/how_to_guide/plot_04_batch_glm.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:24:13.265334 + image/svg+xml @@ -41,12 +41,12 @@ z - - + @@ -82,7 +82,7 @@ z - + @@ -113,7 +113,7 @@ z - + @@ -154,7 +154,7 @@ z - + @@ -203,7 +203,7 @@ z - + @@ -239,7 +239,7 @@ z - + @@ -455,12 +455,12 @@ z - - + @@ -523,7 +523,7 @@ z - + @@ -540,7 +540,7 @@ z - + @@ -557,7 +557,7 @@ z - + @@ -574,7 +574,7 @@ z - + @@ -632,7 +632,7 @@ z - + @@ -1266,7 +1266,7 @@ L 397.186052 63.77007 L 397.836662 69.754119 L 398.487273 85.098222 L 398.487273 85.098222 -" clip-path="url(#p02d2a7eaf1)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p71435c130f)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> + diff --git a/docs/assets/thumbnails/how_to_guide/plot_05_sklearn_pipeline_cv_demo.svg b/docs/assets/thumbnails/how_to_guide/plot_05_sklearn_pipeline_cv_demo.svg index 686d7693..e7359826 100644 --- a/docs/assets/thumbnails/how_to_guide/plot_05_sklearn_pipeline_cv_demo.svg +++ b/docs/assets/thumbnails/how_to_guide/plot_05_sklearn_pipeline_cv_demo.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:24:39.724298 + image/svg+xml @@ -39,7 +39,7 @@ z - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - + - + - + - + - + - + - + - + - + - + - + - - + @@ -1452,12 +1452,12 @@ L -3.5 0 - + - + @@ -1465,12 +1465,12 @@ L -3.5 0 - + - + @@ -1478,12 +1478,12 @@ L -3.5 0 - + - + @@ -1491,12 +1491,12 @@ L -3.5 0 - + - + @@ -1504,12 +1504,12 @@ L -3.5 0 - + - + @@ -1518,12 +1518,12 @@ L -3.5 0 - + - + @@ -1532,32 +1532,18 @@ L -3.5 0 - + - + - - - - - - - - - - - - - - - + @@ -1689,142 +1675,132 @@ z - - + + - - + - + - + - - + - + - + @@ -2023,7 +1999,7 @@ L 280.371563 69.248562 - + diff --git a/docs/assets/thumbnails/how_to_guide/plot_06_glm_pytree.svg b/docs/assets/thumbnails/how_to_guide/plot_06_glm_pytree.svg index 92535cf8..3d6c2801 100644 --- a/docs/assets/thumbnails/how_to_guide/plot_06_glm_pytree.svg +++ b/docs/assets/thumbnails/how_to_guide/plot_06_glm_pytree.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:25:24.201685 + image/svg+xml @@ -72,7 +72,7 @@ z +" clip-path="url(#p1c37c12106)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -132,7 +132,7 @@ z +" clip-path="url(#p1c37c12106)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -193,7 +193,7 @@ z +" clip-path="url(#p1c37c12106)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -240,7 +240,7 @@ z +" clip-path="url(#p1c37c12106)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -304,7 +304,7 @@ z +" clip-path="url(#p1c37c12106)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -361,7 +361,7 @@ z +" clip-path="url(#p1c37c12106)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -403,7 +403,7 @@ z +" clip-path="url(#p1c37c12106)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -431,7 +431,7 @@ z +" clip-path="url(#p1c37c12106)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -464,7 +464,7 @@ C 156.657633 164.879303 158.444777 164.523818 160.112095 163.833192 C 161.779414 163.142566 163.294481 162.130231 164.570591 160.854121 C 165.846701 159.57801 166.859037 158.062943 167.549663 156.395625 C 168.240288 154.728307 168.595773 152.941163 168.595773 151.136471 -" clip-path="url(#pb66cd08c0d)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p1c37c12106)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -492,7 +492,7 @@ C 158.462326 178.622135 162.036613 177.911165 165.37125 176.529914 C 168.705886 175.148662 171.736021 173.123991 174.288241 170.57177 C 176.840461 168.01955 178.865133 164.989415 180.246384 161.654779 C 181.627636 158.320143 182.338606 154.745855 182.338606 151.136471 -" clip-path="url(#pb66cd08c0d)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p1c37c12106)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -520,7 +520,7 @@ C 160.267018 192.364968 165.628449 191.298512 170.630404 189.226635 C 175.632358 187.154758 180.177561 184.117751 184.005891 180.28942 C 187.834221 176.46109 190.871228 171.915888 192.943106 166.913933 C 195.014983 161.911979 196.081438 156.550547 196.081438 151.136471 -" clip-path="url(#pb66cd08c0d)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p1c37c12106)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -580,7 +580,7 @@ C 162.07171 206.1078 169.220285 204.68586 175.889558 201.923357 C 182.558831 199.160853 188.6191 195.111511 193.723541 190.00707 C 198.827981 184.90263 202.877324 178.84236 205.639827 172.173088 C 208.40233 165.503815 209.82427 158.355239 209.82427 151.136471 -" clip-path="url(#pb66cd08c0d)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p1c37c12106)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -608,7 +608,7 @@ C 163.876402 219.850632 172.812121 218.073207 181.148712 214.620078 C 189.485303 211.166949 197.06064 206.105271 203.441191 199.72472 C 209.821741 193.34417 214.88342 185.768833 218.336549 177.432242 C 221.789678 169.095651 223.567103 160.159932 223.567103 151.136471 -" clip-path="url(#pb66cd08c0d)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p1c37c12106)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -650,7 +650,7 @@ L 148.288171 145.22221 L 152.482337 149.766881 L 153.782349 150.788255 L 152.767815 150.91665 -" clip-path="url(#pb66cd08c0d)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1c37c12106)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p35a8c356a4)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -815,7 +815,7 @@ L 405.476471 151.136471 +" clip-path="url(#p35a8c356a4)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -830,7 +830,7 @@ L 383.985 99.251471 +" clip-path="url(#p35a8c356a4)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -845,7 +845,7 @@ L 332.1 77.76 +" clip-path="url(#p35a8c356a4)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -861,7 +861,7 @@ L 280.215 99.251471 +" clip-path="url(#p35a8c356a4)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -877,7 +877,7 @@ L 258.723529 151.136471 +" clip-path="url(#p35a8c356a4)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -893,7 +893,7 @@ L 280.215 203.021471 +" clip-path="url(#p35a8c356a4)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -909,7 +909,7 @@ L 332.1 224.512941 +" clip-path="url(#p35a8c356a4)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -942,7 +942,7 @@ C 334.364064 168.377448 336.606114 167.931476 338.697836 167.065056 C 340.789559 166.198637 342.690277 164.928618 344.291212 163.327682 C 345.892147 161.726747 347.162166 159.82603 348.028586 157.734307 C 348.895006 155.642584 349.340977 153.400535 349.340977 151.136471 -" clip-path="url(#p7ec683f018)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p35a8c356a4)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -970,7 +970,7 @@ C 336.628129 185.618425 341.112227 184.726482 345.295673 182.993642 C 349.479118 181.260802 353.280553 178.720765 356.482424 175.518894 C 359.684294 172.317024 362.224332 168.515589 363.957172 164.332143 C 365.690012 160.148698 366.581954 155.664599 366.581954 151.136471 -" clip-path="url(#p7ec683f018)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p35a8c356a4)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -998,7 +998,7 @@ C 338.892193 202.859402 345.618341 201.521488 351.893509 198.922228 C 358.168677 196.322968 363.87083 192.512912 368.673635 187.710106 C 373.476441 182.9073 377.286498 177.205148 379.885758 170.929979 C 382.485017 164.654811 383.822931 157.928664 383.822931 151.136471 -" clip-path="url(#p7ec683f018)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p35a8c356a4)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1026,7 +1026,7 @@ C 341.156257 220.100379 350.124454 218.316494 358.491345 214.850814 C 366.858236 211.385134 374.461106 206.305059 380.864847 199.901318 C 387.268588 193.497577 392.348664 185.894707 395.814343 177.527816 C 399.280023 169.160925 401.063908 160.192728 401.063908 151.136471 -" clip-path="url(#p7ec683f018)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p35a8c356a4)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1067,7 +1067,7 @@ L 312.334109 133.329201 L 313.661039 140.483576 L 311.68481 144.496331 L 313.788829 149.206052 -" clip-path="url(#p7ec683f018)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p35a8c356a4)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p30db1b4bf9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1159,7 +1159,7 @@ L 582.723529 151.136471 +" clip-path="url(#p30db1b4bf9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1174,7 +1174,7 @@ L 561.232059 99.251471 +" clip-path="url(#p30db1b4bf9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1189,7 +1189,7 @@ L 509.347059 77.76 +" clip-path="url(#p30db1b4bf9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1205,7 +1205,7 @@ L 457.462059 99.251471 +" clip-path="url(#p30db1b4bf9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1221,7 +1221,7 @@ L 435.970588 151.136471 +" clip-path="url(#p30db1b4bf9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1237,7 +1237,7 @@ L 457.462059 203.021471 +" clip-path="url(#p30db1b4bf9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1253,7 +1253,7 @@ L 509.347059 224.512941 +" clip-path="url(#p30db1b4bf9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1286,7 +1286,7 @@ C 512.002703 171.359353 514.632525 170.836249 517.086021 169.819978 C 519.539516 168.803706 521.768972 167.314032 523.646796 165.436208 C 525.52462 163.558383 527.014295 161.328928 528.030566 158.875433 C 529.046837 156.421937 529.569941 153.792115 529.569941 151.136471 -" clip-path="url(#pe0a664dfb9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p30db1b4bf9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1314,7 +1314,7 @@ C 514.658348 191.582235 519.917991 190.536027 524.824983 188.503484 C 529.731974 186.470942 534.190884 183.491593 537.946533 179.735945 C 541.702182 175.980296 544.68153 171.521386 546.714073 166.614395 C 548.746615 161.707403 549.792823 156.44776 549.792823 151.136471 -" clip-path="url(#pe0a664dfb9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p30db1b4bf9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1343,7 +1343,7 @@ C 517.313992 211.805117 525.203458 210.235805 532.563945 207.186991 C 539.924432 204.138178 546.612797 199.669155 552.24627 194.035682 C 557.879743 188.402209 562.348766 181.713843 565.39758 174.353356 C 568.446393 166.99287 570.015705 159.103404 570.015705 151.136471 -" clip-path="url(#pe0a664dfb9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p30db1b4bf9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1385,7 +1385,7 @@ L 498.748434 141.588074 L 471.253761 129.128513 L 461.328848 135.518313 L 439.849835 143.809863 -" clip-path="url(#pe0a664dfb9)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p30db1b4bf9)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4e7bd44d7c)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1477,7 +1477,7 @@ L 228.229412 327.24 +" clip-path="url(#p4e7bd44d7c)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1492,7 +1492,7 @@ L 206.737941 275.355 +" clip-path="url(#p4e7bd44d7c)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1507,7 +1507,7 @@ L 154.852941 253.863529 +" clip-path="url(#p4e7bd44d7c)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1523,7 +1523,7 @@ L 102.967941 275.355 +" clip-path="url(#p4e7bd44d7c)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1539,7 +1539,7 @@ L 81.476471 327.24 +" clip-path="url(#p4e7bd44d7c)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1555,7 +1555,7 @@ L 102.967941 379.125 +" clip-path="url(#p4e7bd44d7c)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1571,7 +1571,7 @@ L 154.852941 400.616471 +" clip-path="url(#p4e7bd44d7c)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1604,7 +1604,7 @@ C 156.50052 339.786407 158.132079 339.46187 159.654243 338.831369 C 161.176408 338.200868 162.559577 337.276664 163.724591 336.11165 C 164.889605 334.946635 165.813809 333.563467 166.44431 332.041302 C 167.074811 330.519138 167.399349 328.887579 167.399349 327.24 -" clip-path="url(#pf120e43782)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p4e7bd44d7c)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1643,7 +1643,7 @@ C 158.148099 352.332815 161.411216 351.683741 164.455546 350.422738 C 167.499875 349.161736 170.266212 347.313328 172.596241 344.9833 C 174.92627 342.653271 176.774677 339.886934 178.035679 336.842605 C 179.296682 333.798275 179.945756 330.535158 179.945756 327.24 -" clip-path="url(#pf120e43782)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p4e7bd44d7c)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1673,7 +1673,7 @@ C 159.795679 364.879222 164.690354 363.905611 169.256848 362.014107 C 173.823342 360.122603 177.972847 357.349993 181.467891 353.854949 C 184.962934 350.359906 187.735545 346.210401 189.627048 341.643907 C 191.518552 337.077413 192.492164 332.182737 192.492164 327.24 -" clip-path="url(#pf120e43782)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p4e7bd44d7c)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1703,7 +1703,7 @@ C 161.443258 377.42563 167.969492 376.127481 174.05815 373.605476 C 180.146809 371.083471 185.679483 367.386657 190.33954 362.726599 C 194.999598 358.066542 198.696412 352.533868 201.218417 346.445209 C 203.740422 340.356551 205.038571 333.830317 205.038571 327.24 -" clip-path="url(#pf120e43782)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p4e7bd44d7c)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1733,7 +1733,7 @@ C 163.090837 389.972037 171.248629 388.349352 178.859453 385.196845 C 186.470276 382.044339 193.386118 377.423321 199.21119 371.598249 C 205.036262 365.773177 209.65728 358.857335 212.809786 351.246511 C 215.962293 343.635688 217.584979 335.477896 217.584979 327.24 -" clip-path="url(#pf120e43782)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p4e7bd44d7c)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1776,7 +1776,7 @@ L 143.208905 316.749783 L 135.807767 316.236873 L 136.868987 321.390631 L 144.383144 326.136242 -" clip-path="url(#pf120e43782)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4e7bd44d7c)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbcb341c52e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1868,7 +1868,7 @@ L 405.476471 327.24 +" clip-path="url(#pbcb341c52e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1883,7 +1883,7 @@ L 383.985 275.355 +" clip-path="url(#pbcb341c52e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1898,7 +1898,7 @@ L 332.1 253.863529 +" clip-path="url(#pbcb341c52e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1914,7 +1914,7 @@ L 280.215 275.355 +" clip-path="url(#pbcb341c52e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1930,7 +1930,7 @@ L 258.723529 327.24 +" clip-path="url(#pbcb341c52e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1946,7 +1946,7 @@ L 280.215 379.125 +" clip-path="url(#pbcb341c52e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1962,7 +1962,7 @@ L 332.1 400.616471 +" clip-path="url(#pbcb341c52e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -1995,7 +1995,7 @@ C 333.870113 340.71951 335.623014 340.370837 337.258385 339.693444 C 338.893757 339.016051 340.379794 338.023112 341.631453 336.771453 C 342.883112 335.519794 343.876051 334.033757 344.553444 332.398385 C 345.230837 330.763014 345.57951 329.010113 345.57951 327.24 -" clip-path="url(#p2480407013)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pbcb341c52e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2023,7 +2023,7 @@ C 335.640226 354.199021 339.146028 353.501673 342.416771 352.146888 C 345.687513 350.792102 348.659588 348.806224 351.162906 346.302906 C 353.666224 343.799588 355.652102 340.827513 357.006888 337.556771 C 358.361673 334.286028 359.059021 330.780226 359.059021 327.24 -" clip-path="url(#p2480407013)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pbcb341c52e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2051,7 +2051,7 @@ C 337.410339 367.678531 342.669042 366.63251 347.575156 364.600331 C 352.48127 362.568152 356.939383 359.589337 360.69436 355.83436 C 364.449337 352.079383 367.428152 347.62127 369.460331 342.715156 C 371.49251 337.809042 372.538531 332.550339 372.538531 327.24 -" clip-path="url(#p2480407013)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pbcb341c52e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2079,7 +2079,7 @@ C 339.180452 381.158042 346.192056 379.763347 352.733541 377.053775 C 359.275026 374.344203 365.219177 370.372449 370.225813 365.365813 C 375.232449 360.359177 379.204203 354.415026 381.913775 347.873541 C 384.623347 341.332056 386.018042 334.320452 386.018042 327.24 -" clip-path="url(#p2480407013)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pbcb341c52e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2107,7 +2107,7 @@ C 340.950565 394.637552 349.71507 392.894184 357.891927 389.507219 C 366.068783 386.120254 373.498971 381.155561 379.757266 374.897266 C 386.015561 368.638971 390.980254 361.208783 394.367219 353.031927 C 397.754184 344.85507 399.497552 336.090565 399.497552 327.24 -" clip-path="url(#p2480407013)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pbcb341c52e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2148,7 +2148,7 @@ L 317.38232 313.980709 L 318.148906 319.179919 L 321.179176 323.687949 L 323.919303 326.377566 -" clip-path="url(#p2480407013)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbcb341c52e)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9ad4016414)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2240,7 +2240,7 @@ L 582.723529 327.24 +" clip-path="url(#p9ad4016414)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2255,7 +2255,7 @@ L 561.232059 275.355 +" clip-path="url(#p9ad4016414)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2270,7 +2270,7 @@ L 509.347059 253.863529 +" clip-path="url(#p9ad4016414)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2286,7 +2286,7 @@ L 457.462059 275.355 +" clip-path="url(#p9ad4016414)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2302,7 +2302,7 @@ L 435.970588 327.24 +" clip-path="url(#p9ad4016414)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2318,7 +2318,7 @@ L 457.462059 379.125 +" clip-path="url(#p9ad4016414)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2334,7 +2334,7 @@ L 509.347059 400.616471 +" clip-path="url(#p9ad4016414)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2367,7 +2367,7 @@ C 511.480087 343.483132 513.592375 343.062972 515.563036 342.246697 C 517.533698 341.430423 519.324409 340.233908 520.832688 338.725629 C 522.340967 337.21735 523.537481 335.426639 524.353756 333.455978 C 525.170031 331.485316 525.590191 329.373029 525.590191 327.24 -" clip-path="url(#pd02bf96ddd)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p9ad4016414)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2397,7 +2397,7 @@ C 513.613116 359.726264 517.837691 358.885944 521.779014 357.253395 C 525.720337 355.620845 529.301759 353.227816 532.318317 350.211258 C 535.334874 347.1947 537.727904 343.613278 539.360453 339.671955 C 540.993003 335.730632 541.833323 331.506057 541.833323 327.24 -" clip-path="url(#pd02bf96ddd)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p9ad4016414)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2427,7 +2427,7 @@ C 515.746145 375.969396 522.083007 374.708916 527.994991 372.260092 C 533.906976 369.811268 539.279109 366.221724 543.803945 361.696887 C 548.328782 357.17205 551.918327 351.799917 554.367151 345.887933 C 556.815975 339.975948 558.076455 333.639086 558.076455 327.24 -" clip-path="url(#pd02bf96ddd)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p9ad4016414)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2457,7 +2457,7 @@ C 517.879173 392.212528 526.328323 390.531888 534.210969 387.266789 C 542.093615 384.00169 549.256458 379.215631 555.289574 373.182515 C 561.32269 367.1494 566.108749 359.986556 569.373848 352.10391 C 572.638947 344.221264 574.319587 335.772114 574.319587 327.24 -" clip-path="url(#pd02bf96ddd)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p9ad4016414)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2500,7 +2500,7 @@ L 483.631083 304.072245 L 481.328057 311.052349 L 466.830606 313.411317 L 463.754108 322.433453 -" clip-path="url(#pd02bf96ddd)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9ad4016414)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa6e1d735a1)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2592,7 +2592,7 @@ L 228.229412 503.343529 +" clip-path="url(#pa6e1d735a1)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2607,7 +2607,7 @@ L 206.737941 451.458529 +" clip-path="url(#pa6e1d735a1)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2622,7 +2622,7 @@ L 154.852941 429.967059 +" clip-path="url(#pa6e1d735a1)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2638,7 +2638,7 @@ L 102.967941 451.458529 +" clip-path="url(#pa6e1d735a1)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2654,7 +2654,7 @@ L 81.476471 503.343529 +" clip-path="url(#pa6e1d735a1)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2670,7 +2670,7 @@ L 102.967941 555.228529 +" clip-path="url(#pa6e1d735a1)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2686,7 +2686,7 @@ L 154.852941 576.72 +" clip-path="url(#pa6e1d735a1)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2719,7 +2719,7 @@ C 156.40566 515.167571 157.943281 514.861719 159.377806 514.267519 C 160.812331 513.673319 162.115863 512.802327 163.213801 511.704389 C 164.311739 510.606451 165.182731 509.302919 165.776931 507.868394 C 166.371131 506.433869 166.676982 504.896248 166.676982 503.343529 -" clip-path="url(#p374c4e0d24)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pa6e1d735a1)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2750,7 +2750,7 @@ C 157.958379 526.991612 161.03362 526.379908 163.902671 525.191509 C 166.771721 524.003109 169.378785 522.261125 171.574661 520.065249 C 173.770537 517.869373 175.512521 515.262309 176.700921 512.393259 C 177.88932 509.524208 178.501024 506.448967 178.501024 503.343529 -" clip-path="url(#p374c4e0d24)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pa6e1d735a1)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2781,7 +2781,7 @@ C 159.511098 538.815653 164.12396 537.898098 168.427535 536.115499 C 172.731111 534.332899 176.641706 531.719923 179.935521 528.426109 C 183.229335 525.132295 185.842311 521.221699 187.62491 516.918124 C 189.40751 512.614548 190.325065 508.001686 190.325065 503.343529 -" clip-path="url(#p374c4e0d24)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pa6e1d735a1)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2812,7 +2812,7 @@ C 161.063817 550.639695 167.214299 549.416288 172.9524 547.039488 C 178.690501 544.662689 183.904628 541.178721 188.29638 536.786969 C 192.688132 532.395216 196.172101 527.181089 198.5489 521.442988 C 200.925699 515.704887 202.149106 509.554405 202.149106 503.343529 -" clip-path="url(#p374c4e0d24)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pa6e1d735a1)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2843,7 +2843,7 @@ C 162.616536 562.463736 170.304639 560.934477 177.477265 557.963478 C 184.649891 554.992479 191.16755 550.637519 196.65724 545.147828 C 202.14693 539.658138 206.501891 533.140479 209.47289 525.967853 C 212.443889 518.795227 213.973148 511.107124 213.973148 503.343529 -" clip-path="url(#p374c4e0d24)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pa6e1d735a1)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2874,7 +2874,7 @@ C 164.169254 574.287777 173.394978 572.452667 182.002129 568.887468 C 190.609281 565.322269 198.430472 560.096316 205.0181 553.508688 C 211.605728 546.92106 216.831681 539.099869 220.39688 530.492718 C 223.962078 521.885567 225.797189 512.659843 225.797189 503.343529 -" clip-path="url(#p374c4e0d24)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#pa6e1d735a1)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -2918,7 +2918,7 @@ L 153.561927 502.180443 L 154.852941 503.343529 L 153.379157 502.864174 L 154.852941 503.343529 -" clip-path="url(#p374c4e0d24)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa6e1d735a1)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7994f8fc7e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3010,7 +3010,7 @@ L 405.476471 503.343529 +" clip-path="url(#p7994f8fc7e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3025,7 +3025,7 @@ L 383.985 451.458529 +" clip-path="url(#p7994f8fc7e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3040,7 +3040,7 @@ L 332.1 429.967059 +" clip-path="url(#p7994f8fc7e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3056,7 +3056,7 @@ L 280.215 451.458529 +" clip-path="url(#p7994f8fc7e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3072,7 +3072,7 @@ L 258.723529 503.343529 +" clip-path="url(#p7994f8fc7e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3088,7 +3088,7 @@ L 280.215 555.228529 +" clip-path="url(#p7994f8fc7e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3104,7 +3104,7 @@ L 332.1 576.72 +" clip-path="url(#p7994f8fc7e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3137,7 +3137,7 @@ C 333.818737 516.431807 335.520761 516.093253 337.108667 515.435521 C 338.696573 514.777789 340.139479 513.813669 341.35481 512.598339 C 342.57014 511.383009 343.534259 509.940102 344.191991 508.352196 C 344.849724 506.764291 345.188277 505.062266 345.188277 503.343529 -" clip-path="url(#p8353e7c1e6)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p7994f8fc7e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3165,7 +3165,7 @@ C 335.537474 529.520084 338.941522 528.842977 342.117334 527.527512 C 345.293145 526.212048 348.178958 524.28381 350.609619 521.853149 C 353.04028 519.422488 354.968519 516.536675 356.283983 513.360863 C 357.599447 510.185052 358.276554 506.781003 358.276554 503.343529 -" clip-path="url(#p8353e7c1e6)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p7994f8fc7e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3193,7 +3193,7 @@ C 337.25621 542.608361 342.362283 541.5927 347.126001 539.619504 C 351.889718 537.646307 356.218437 534.75395 359.864429 531.107958 C 363.51042 527.461967 366.402778 523.133247 368.375974 518.36953 C 370.349171 513.605813 371.364832 508.49974 371.364832 503.343529 -" clip-path="url(#p8353e7c1e6)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p7994f8fc7e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3221,7 +3221,7 @@ C 338.974947 555.696638 345.783044 554.342424 352.134667 551.711495 C 358.486291 549.080567 364.257917 545.22409 369.119238 540.362768 C 373.98056 535.501446 377.837037 529.72982 380.467966 523.378197 C 383.098894 517.026574 384.453109 510.218477 384.453109 503.343529 -" clip-path="url(#p8353e7c1e6)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p7994f8fc7e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3249,7 +3249,7 @@ C 340.693684 568.784916 349.203805 567.092147 357.143334 563.803487 C 365.082863 560.514826 372.297396 555.69423 378.374048 549.617577 C 384.4507 543.540925 389.271297 536.326393 392.559957 528.386864 C 395.848618 520.447335 397.541386 511.937214 397.541386 503.343529 -" clip-path="url(#p8353e7c1e6)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> +" clip-path="url(#p7994f8fc7e)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> @@ -3290,7 +3290,7 @@ L 319.595804 492.078386 L 321.714601 497.343486 L 317.82558 498.700705 L 325.646103 502.66314 -" clip-path="url(#p8353e7c1e6)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7994f8fc7e)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> + - + - + - + - + - + - + - + - 2024-11-21T17:25:39.341677 + image/svg+xml @@ -43,7 +43,7 @@ L 144.371629 144.845217 L 144.371629 60.48 L 106.353262 60.48 z -" clip-path="url(#pdc08b8ccdb)" style="fill: #ffcc00; opacity: 0.4; stroke: #ffcc00; stroke-linejoin: miter"/> +" clip-path="url(#pe3061b6ffa)" style="fill: #ffcc00; opacity: 0.4; stroke: #ffcc00; stroke-linejoin: miter"/> +" clip-path="url(#pe3061b6ffa)" style="fill: #ff8000; opacity: 0.4; stroke: #ff8000; stroke-linejoin: miter"/> +" clip-path="url(#pe3061b6ffa)" style="fill: #ff3300; opacity: 0.4; stroke: #ff3300; stroke-linejoin: miter"/> - - + - + - + - + - + - + - + @@ -121,12 +121,12 @@ L 0 3.5 - - + @@ -162,7 +162,7 @@ z - + @@ -203,7 +203,7 @@ z - + @@ -2574,7 +2574,7 @@ L 347.135933 102.001083 L 347.247453 141.010435 L 435.845455 141.010435 L 435.845455 141.010435 -" clip-path="url(#pdc08b8ccdb)" style="fill: none; stroke: #808080; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe3061b6ffa)" style="fill: none; stroke: #808080; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p44ca689fb2)" style="fill: #ffcc00; opacity: 0.4; stroke: #ffcc00; stroke-linejoin: miter"/> +" clip-path="url(#p44ca689fb2)" style="fill: #ff8000; opacity: 0.4; stroke: #ff8000; stroke-linejoin: miter"/> +" clip-path="url(#p44ca689fb2)" style="fill: #ff3300; opacity: 0.4; stroke: #ff3300; stroke-linejoin: miter"/> - + @@ -2786,7 +2786,7 @@ z - + @@ -2801,7 +2801,7 @@ z - + @@ -2828,7 +2828,7 @@ z - + @@ -2843,7 +2843,7 @@ z - + @@ -2899,7 +2899,7 @@ z - + @@ -2914,7 +2914,7 @@ z - + @@ -3063,7 +3063,7 @@ z - + @@ -3076,7 +3076,7 @@ z - + @@ -3090,7 +3090,7 @@ z - + @@ -3130,7 +3130,7 @@ z - + @@ -3519,7 +3519,7 @@ L 347.994704 238.694945 L 348.919849 238.721029 L 435.845455 238.721067 L 435.845455 238.721067 -" clip-path="url(#pf3d39575ad)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p44ca689fb2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p44ca689fb2)" style="fill: none; stroke: #ff6347; stroke-width: 1.5; stroke-linecap: square"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4022,7 +4022,7 @@ z - + @@ -4076,7 +4076,7 @@ z - + @@ -4091,7 +4091,7 @@ z - + @@ -4106,7 +4106,7 @@ z - + @@ -4136,7 +4136,7 @@ z - + @@ -4160,7 +4160,7 @@ z - + @@ -4175,7 +4175,7 @@ z - + @@ -4190,7 +4190,7 @@ z - + @@ -4205,7 +4205,7 @@ z - + @@ -4243,7 +4243,7 @@ z +" clip-path="url(#p2860d16ec5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> @@ -4389,7 +4389,7 @@ L 170.292366 294.44427 L 171.26745 304.047457 L 172.660428 317.946596 L 172.660428 317.946596 -" clip-path="url(#pdca778fba3)" style="fill: none; stroke: #ff6347; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2860d16ec5)" style="fill: none; stroke: #ff6347; stroke-width: 1.5; stroke-linecap: square"/> - + @@ -4440,7 +4440,7 @@ z - + @@ -4455,7 +4455,7 @@ z - + @@ -4485,7 +4485,7 @@ z - + @@ -4498,7 +4498,7 @@ z - + @@ -4511,7 +4511,7 @@ z - + @@ -4525,7 +4525,7 @@ z - + @@ -4539,7 +4539,7 @@ z - + @@ -4668,22 +4668,22 @@ L 289.65941 338.308585 L 291.644404 338.34365 L 310.519251 338.343907 L 310.519251 338.343907 -" clip-path="url(#p04163e9e16)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p57cd9c49f6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> - - - - - - - - - - - - - + + + + + + + + + + + + + @@ -4776,7 +4776,7 @@ L 307.663647 332.826592 L 308.499434 333.906454 L 310.519251 336.643194 L 310.519251 336.643194 -" clip-path="url(#p04163e9e16)" style="fill: none; stroke: #ff6347; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p57cd9c49f6)" style="fill: none; stroke: #ff6347; stroke-width: 1.5; stroke-linecap: square"/> - + @@ -4827,7 +4827,7 @@ z - + @@ -4842,7 +4842,7 @@ z - + @@ -4872,7 +4872,7 @@ z - + @@ -4885,7 +4885,7 @@ z - + @@ -4899,7 +4899,7 @@ z - + @@ -4913,7 +4913,7 @@ z - + @@ -5099,38 +5099,38 @@ L 447.333342 334.796436 L 447.925357 337.225652 L 448.378075 338.40525 L 448.378075 338.40525 -" clip-path="url(#pf509139387)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd078dfb39c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -5282,7 +5282,7 @@ L 446.323433 321.526368 L 448.02983 332.702555 L 448.378075 334.352229 L 448.378075 334.352229 -" clip-path="url(#pf509139387)" style="fill: none; stroke: #ff6347; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd078dfb39c)" style="fill: none; stroke: #ff6347; stroke-width: 1.5; stroke-linecap: square"/> + - + - + - + - + diff --git a/docs/assets/thumbnails/tutorials/plot_02_head_direction.svg b/docs/assets/thumbnails/tutorials/plot_02_head_direction.svg index 7287c79b..334d668a 100644 --- a/docs/assets/thumbnails/tutorials/plot_02_head_direction.svg +++ b/docs/assets/thumbnails/tutorials/plot_02_head_direction.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:26:02.746370 + image/svg+xml @@ -43,7 +43,7 @@ L 113.445378 87.755294 L 113.445378 69.12 L 90 69.12 z -" clip-path="url(#p9590a81315)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p749bd91796)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -128,12 +128,12 @@ L 111.570287 80.646993 L 111.840085 80.657057 L 112.109882 80.662992 L 112.379679 80.664939 -" clip-path="url(#p9590a81315)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p749bd91796)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p749bd91796)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -151,7 +151,7 @@ L 141.579832 87.755294 L 141.579832 69.12 L 118.134454 69.12 z -" clip-path="url(#ped2653a965)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> +" clip-path="url(#pd768d4130d)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> @@ -236,12 +236,12 @@ L 139.704741 80.675468 L 139.974538 80.669563 L 140.244336 80.666081 L 140.514133 80.664939 -" clip-path="url(#ped2653a965)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd768d4130d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd768d4130d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -259,7 +259,7 @@ L 169.714286 87.755294 L 169.714286 69.12 L 146.268908 69.12 z -" clip-path="url(#p21e72f14b9)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> +" clip-path="url(#p1394ed9a7c)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> @@ -344,12 +344,12 @@ L 167.839195 80.658153 L 168.108992 80.661958 L 168.378789 80.664202 L 168.648587 80.664939 -" clip-path="url(#p21e72f14b9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1394ed9a7c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1394ed9a7c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -367,7 +367,7 @@ L 197.848739 87.755294 L 197.848739 69.12 L 174.403361 69.12 z -" clip-path="url(#pd888b325d1)" style="fill: #ff7d7d; opacity: 0.5; stroke: #ff7d7d; stroke-linejoin: miter"/> +" clip-path="url(#pe376209ed7)" style="fill: #ff7d7d; opacity: 0.5; stroke: #ff7d7d; stroke-linejoin: miter"/> @@ -452,12 +452,12 @@ L 195.973649 80.651515 L 196.243446 80.659043 L 196.513243 80.663482 L 196.78304 80.664939 -" clip-path="url(#pd888b325d1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe376209ed7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe376209ed7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -475,7 +475,7 @@ L 225.983193 87.755294 L 225.983193 69.12 L 202.537815 69.12 z -" clip-path="url(#p95efffb43f)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> +" clip-path="url(#p777d0e3c7e)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> @@ -560,12 +560,12 @@ L 224.108103 80.667353 L 224.3779 80.665999 L 224.647697 80.665201 L 224.917494 80.664939 -" clip-path="url(#p95efffb43f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p777d0e3c7e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p777d0e3c7e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -583,7 +583,7 @@ L 254.117647 87.755294 L 254.117647 69.12 L 230.672269 69.12 z -" clip-path="url(#p1ef9ae295b)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#pe63b49d62a)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -668,12 +668,12 @@ L 252.242556 80.665808 L 252.512354 80.66532 L 252.782151 80.665033 L 253.051948 80.664939 -" clip-path="url(#p1ef9ae295b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe63b49d62a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe63b49d62a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -691,7 +691,7 @@ L 282.252101 87.755294 L 282.252101 69.12 L 258.806723 69.12 z -" clip-path="url(#p5c85405ac8)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> +" clip-path="url(#p2957cd5942)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> @@ -776,12 +776,12 @@ L 280.37701 80.673901 L 280.646807 80.668875 L 280.916605 80.665911 L 281.186402 80.664939 -" clip-path="url(#p5c85405ac8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2957cd5942)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2957cd5942)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -799,7 +799,7 @@ L 310.386555 87.755294 L 310.386555 69.12 L 286.941176 69.12 z -" clip-path="url(#p95abf522b5)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> +" clip-path="url(#p3d94b5e082)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> @@ -884,12 +884,12 @@ L 308.511464 80.678772 L 308.781261 80.671014 L 309.051058 80.666439 L 309.320856 80.664939 -" clip-path="url(#p95abf522b5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3d94b5e082)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3d94b5e082)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -907,7 +907,7 @@ L 338.521008 87.755294 L 338.521008 69.12 L 315.07563 69.12 z -" clip-path="url(#p3771ff3267)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> +" clip-path="url(#p2f7c627769)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> @@ -992,12 +992,12 @@ L 336.645918 80.677684 L 336.915715 80.670536 L 337.185512 80.666321 L 337.455309 80.664939 -" clip-path="url(#p3771ff3267)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2f7c627769)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2f7c627769)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1015,7 +1015,7 @@ L 366.655462 87.755294 L 366.655462 69.12 L 343.210084 69.12 z -" clip-path="url(#pf7bf9e5299)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> +" clip-path="url(#p2980f04847)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> @@ -1100,12 +1100,12 @@ L 364.780372 80.667048 L 365.050169 80.665865 L 365.319966 80.665167 L 365.589763 80.664939 -" clip-path="url(#pf7bf9e5299)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2980f04847)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2980f04847)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1123,7 +1123,7 @@ L 394.789916 87.755294 L 394.789916 69.12 L 371.344538 69.12 z -" clip-path="url(#pf0a5849ca8)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> +" clip-path="url(#p479377c119)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> @@ -1208,12 +1208,12 @@ L 392.914825 80.672311 L 393.184623 80.668177 L 393.45442 80.665738 L 393.724217 80.664939 -" clip-path="url(#pf0a5849ca8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p479377c119)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p479377c119)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1231,7 +1231,7 @@ L 422.92437 87.755294 L 422.92437 69.12 L 399.478992 69.12 z -" clip-path="url(#p200316afb5)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> +" clip-path="url(#pf990074572)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> @@ -1316,12 +1316,12 @@ L 421.049279 80.65606 L 421.319076 80.661039 L 421.588874 80.663975 L 421.858671 80.664939 -" clip-path="url(#p200316afb5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf990074572)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf990074572)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1339,7 +1339,7 @@ L 451.058824 87.755294 L 451.058824 69.12 L 427.613445 69.12 z -" clip-path="url(#pad92a48111)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> +" clip-path="url(#p06eae94a49)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> @@ -1424,12 +1424,12 @@ L 449.183733 80.676724 L 449.45353 80.670115 L 449.723327 80.666217 L 449.993125 80.664939 -" clip-path="url(#pad92a48111)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p06eae94a49)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p06eae94a49)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1447,7 +1447,7 @@ L 479.193277 87.755294 L 479.193277 69.12 L 455.747899 69.12 z -" clip-path="url(#p3421216d71)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> +" clip-path="url(#p581a58f864)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> @@ -1532,12 +1532,12 @@ L 477.318187 80.667773 L 477.587984 80.666183 L 477.857781 80.665246 L 478.127578 80.664939 -" clip-path="url(#p3421216d71)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p581a58f864)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p581a58f864)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1555,7 +1555,7 @@ L 507.327731 87.755294 L 507.327731 69.12 L 483.882353 69.12 z -" clip-path="url(#pc6344fed43)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> +" clip-path="url(#p5d013bdbd2)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> @@ -1640,12 +1640,12 @@ L 505.45264 80.664428 L 505.722438 80.664714 L 505.992235 80.664883 L 506.262032 80.664939 -" clip-path="url(#pc6344fed43)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5d013bdbd2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5d013bdbd2)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1663,7 +1663,7 @@ L 535.462185 87.755294 L 535.462185 69.12 L 512.016807 69.12 z -" clip-path="url(#p9c3388eefb)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> +" clip-path="url(#pe72a889779)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> @@ -1748,12 +1748,12 @@ L 533.587094 80.672024 L 533.856891 80.66805 L 534.126689 80.665707 L 534.396486 80.664939 -" clip-path="url(#p9c3388eefb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe72a889779)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe72a889779)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1771,7 +1771,7 @@ L 563.596639 87.755294 L 563.596639 69.12 L 540.151261 69.12 z -" clip-path="url(#p64e53a82c9)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> +" clip-path="url(#p2f04c25cd0)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> @@ -1856,12 +1856,12 @@ L 561.721548 80.665934 L 561.991345 80.665376 L 562.261142 80.665047 L 562.53094 80.664939 -" clip-path="url(#p64e53a82c9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2f04c25cd0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2f04c25cd0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1879,7 +1879,7 @@ L 591.731092 87.755294 L 591.731092 69.12 L 568.285714 69.12 z -" clip-path="url(#p650d99ddf4)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> +" clip-path="url(#pf831f2c634)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> @@ -1964,12 +1964,12 @@ L 589.856002 80.685519 L 590.125799 80.673978 L 590.395596 80.667171 L 590.665393 80.664939 -" clip-path="url(#p650d99ddf4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf831f2c634)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf831f2c634)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -1987,7 +1987,7 @@ L 619.865546 87.755294 L 619.865546 69.12 L 596.420168 69.12 z -" clip-path="url(#p7ab432cdc6)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#p388a77c08b)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -2072,12 +2072,12 @@ L 617.990456 80.670055 L 618.260253 80.667186 L 618.53005 80.665494 L 618.799847 80.664939 -" clip-path="url(#p7ab432cdc6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p388a77c08b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p388a77c08b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2095,7 +2095,7 @@ L 113.445378 110.117647 L 113.445378 91.482353 L 90 91.482353 z -" clip-path="url(#pa3f2babd0f)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> +" clip-path="url(#pa02e039027)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> @@ -2180,12 +2180,12 @@ L 111.570287 102.767724 L 111.840085 102.769162 L 112.109882 102.77001 L 112.379679 102.770289 -" clip-path="url(#pa3f2babd0f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa02e039027)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa02e039027)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2203,7 +2203,7 @@ L 141.579832 110.117647 L 141.579832 91.482353 L 118.134454 91.482353 z -" clip-path="url(#p0a6ae21062)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#pb4f97f90dc)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -2288,12 +2288,12 @@ L 139.704741 102.758326 L 139.974538 102.765035 L 140.244336 102.768991 L 140.514133 102.770289 -" clip-path="url(#p0a6ae21062)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb4f97f90dc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb4f97f90dc)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2311,7 +2311,7 @@ L 169.714286 110.117647 L 169.714286 91.482353 L 146.268908 91.482353 z -" clip-path="url(#p6499c9de80)" style="fill: #ffbdbd; opacity: 0.5; stroke: #ffbdbd; stroke-linejoin: miter"/> +" clip-path="url(#p492bed7f29)" style="fill: #ffbdbd; opacity: 0.5; stroke: #ffbdbd; stroke-linejoin: miter"/> @@ -2396,12 +2396,12 @@ L 167.839195 102.771472 L 168.108992 102.770809 L 168.378789 102.770417 L 168.648587 102.770289 -" clip-path="url(#p6499c9de80)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p492bed7f29)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p492bed7f29)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2419,7 +2419,7 @@ L 197.848739 110.117647 L 197.848739 91.482353 L 174.403361 91.482353 z -" clip-path="url(#p60047dcf36)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> +" clip-path="url(#pff67949c8d)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> @@ -2504,12 +2504,12 @@ L 195.973649 102.765973 L 196.243446 102.768393 L 196.513243 102.769821 L 196.78304 102.770289 -" clip-path="url(#p60047dcf36)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pff67949c8d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pff67949c8d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2527,7 +2527,7 @@ L 225.983193 110.117647 L 225.983193 91.482353 L 202.537815 91.482353 z -" clip-path="url(#pc379ed8b79)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> +" clip-path="url(#pdf5551986a)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> @@ -2612,12 +2612,12 @@ L 224.108103 102.773462 L 224.3779 102.771683 L 224.647697 102.770633 L 224.917494 102.770289 -" clip-path="url(#pc379ed8b79)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdf5551986a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdf5551986a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2635,7 +2635,7 @@ L 254.117647 110.117647 L 254.117647 91.482353 L 230.672269 91.482353 z -" clip-path="url(#pf03389d2f9)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> +" clip-path="url(#p04784c58db)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> @@ -2720,12 +2720,12 @@ L 252.242556 102.778909 L 252.512354 102.774075 L 252.782151 102.771224 L 253.051948 102.770289 -" clip-path="url(#pf03389d2f9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p04784c58db)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p04784c58db)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2743,7 +2743,7 @@ L 282.252101 110.117647 L 282.252101 91.482353 L 258.806723 91.482353 z -" clip-path="url(#p3eae332b79)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#p8eda2fb51f)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -2828,12 +2828,12 @@ L 280.37701 102.770016 L 280.646807 102.770169 L 280.916605 102.770259 L 281.186402 102.770289 -" clip-path="url(#p3eae332b79)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8eda2fb51f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8eda2fb51f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2851,7 +2851,7 @@ L 310.386555 110.117647 L 310.386555 91.482353 L 286.941176 91.482353 z -" clip-path="url(#p20af343335)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#p32c281ea21)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -2936,12 +2936,12 @@ L 308.511464 102.773679 L 308.781261 102.771778 L 309.051058 102.770657 L 309.320856 102.770289 -" clip-path="url(#p20af343335)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p32c281ea21)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p32c281ea21)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -2959,7 +2959,7 @@ L 338.521008 110.117647 L 338.521008 91.482353 L 315.07563 91.482353 z -" clip-path="url(#p382751b9e5)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> +" clip-path="url(#p0e2b1dc98f)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> @@ -3044,12 +3044,12 @@ L 336.645918 102.768967 L 336.915715 102.769708 L 337.185512 102.770145 L 337.455309 102.770289 -" clip-path="url(#p382751b9e5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0e2b1dc98f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0e2b1dc98f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3067,7 +3067,7 @@ L 366.655462 110.117647 L 366.655462 91.482353 L 343.210084 91.482353 z -" clip-path="url(#pb7e90b8788)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#pbe68f6726c)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -3152,12 +3152,12 @@ L 364.780372 102.764435 L 365.050169 102.767718 L 365.319966 102.769654 L 365.589763 102.770289 -" clip-path="url(#pb7e90b8788)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbe68f6726c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbe68f6726c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3175,7 +3175,7 @@ L 394.789916 110.117647 L 394.789916 91.482353 L 371.344538 91.482353 z -" clip-path="url(#pb93a46db6b)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#pf6747ec560)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -3260,12 +3260,12 @@ L 392.914825 102.766145 L 393.184623 102.768469 L 393.45442 102.769839 L 393.724217 102.770289 -" clip-path="url(#pb93a46db6b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf6747ec560)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf6747ec560)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3283,7 +3283,7 @@ L 422.92437 110.117647 L 422.92437 91.482353 L 399.478992 91.482353 z -" clip-path="url(#pcc56fa2cda)" style="fill: #ffb1b1; opacity: 0.5; stroke: #ffb1b1; stroke-linejoin: miter"/> +" clip-path="url(#p745b90145d)" style="fill: #ffb1b1; opacity: 0.5; stroke: #ffb1b1; stroke-linejoin: miter"/> @@ -3368,12 +3368,12 @@ L 421.049279 102.771276 L 421.319076 102.770722 L 421.588874 102.770396 L 421.858671 102.770289 -" clip-path="url(#pcc56fa2cda)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p745b90145d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p745b90145d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3391,7 +3391,7 @@ L 451.058824 110.117647 L 451.058824 91.482353 L 427.613445 91.482353 z -" clip-path="url(#p7bfee2d109)" style="fill: #8585ff; opacity: 0.5; stroke: #8585ff; stroke-linejoin: miter"/> +" clip-path="url(#p41d90b6b66)" style="fill: #8585ff; opacity: 0.5; stroke: #8585ff; stroke-linejoin: miter"/> @@ -3476,12 +3476,12 @@ L 449.183733 102.785121 L 449.45353 102.776803 L 449.723327 102.771898 L 449.993125 102.770289 -" clip-path="url(#p7bfee2d109)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p41d90b6b66)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p41d90b6b66)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3499,7 +3499,7 @@ L 479.193277 110.117647 L 479.193277 91.482353 L 455.747899 91.482353 z -" clip-path="url(#p4ad6db2323)" style="fill: #ffbdbd; opacity: 0.5; stroke: #ffbdbd; stroke-linejoin: miter"/> +" clip-path="url(#pc959a5a78b)" style="fill: #ffbdbd; opacity: 0.5; stroke: #ffbdbd; stroke-linejoin: miter"/> @@ -3584,12 +3584,12 @@ L 477.318187 102.761584 L 477.587984 102.766466 L 477.857781 102.769344 L 478.127578 102.770289 -" clip-path="url(#p4ad6db2323)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc959a5a78b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc959a5a78b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3607,7 +3607,7 @@ L 507.327731 110.117647 L 507.327731 91.482353 L 483.882353 91.482353 z -" clip-path="url(#p12a77b8c26)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#p827f555640)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -3692,12 +3692,12 @@ L 505.45264 102.779033 L 505.722438 102.774129 L 505.992235 102.771237 L 506.262032 102.770289 -" clip-path="url(#p12a77b8c26)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p827f555640)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p827f555640)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3715,7 +3715,7 @@ L 535.462185 110.117647 L 535.462185 91.482353 L 512.016807 91.482353 z -" clip-path="url(#p73580380b9)" style="fill: #ffc5c5; opacity: 0.5; stroke: #ffc5c5; stroke-linejoin: miter"/> +" clip-path="url(#pf9bee455ae)" style="fill: #ffc5c5; opacity: 0.5; stroke: #ffc5c5; stroke-linejoin: miter"/> @@ -3800,12 +3800,12 @@ L 533.587094 102.762505 L 533.856891 102.76687 L 534.126689 102.769444 L 534.396486 102.770289 -" clip-path="url(#p73580380b9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf9bee455ae)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf9bee455ae)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3823,7 +3823,7 @@ L 563.596639 110.117647 L 563.596639 91.482353 L 540.151261 91.482353 z -" clip-path="url(#p425002ee93)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> +" clip-path="url(#p1c0ac6d551)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> @@ -3908,12 +3908,12 @@ L 561.721548 102.773989 L 561.991345 102.771914 L 562.261142 102.77069 L 562.53094 102.770289 -" clip-path="url(#p425002ee93)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1c0ac6d551)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1c0ac6d551)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -3931,7 +3931,7 @@ L 591.731092 110.117647 L 591.731092 91.482353 L 568.285714 91.482353 z -" clip-path="url(#p5e78a0206a)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> +" clip-path="url(#p32e45246f5)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> @@ -4016,12 +4016,12 @@ L 589.856002 102.786793 L 590.125799 102.777538 L 590.395596 102.772079 L 590.665393 102.770289 -" clip-path="url(#p5e78a0206a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p32e45246f5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p32e45246f5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4039,7 +4039,7 @@ L 619.865546 110.117647 L 619.865546 91.482353 L 596.420168 91.482353 z -" clip-path="url(#pc6037ca084)" style="fill: #adadff; opacity: 0.5; stroke: #adadff; stroke-linejoin: miter"/> +" clip-path="url(#p4597b2dc9c)" style="fill: #adadff; opacity: 0.5; stroke: #adadff; stroke-linejoin: miter"/> @@ -4124,12 +4124,12 @@ L 617.990456 102.780009 L 618.260253 102.774558 L 618.53005 102.771343 L 618.799847 102.770289 -" clip-path="url(#pc6037ca084)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4597b2dc9c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4597b2dc9c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4147,7 +4147,7 @@ L 113.445378 132.48 L 113.445378 113.844706 L 90 113.844706 z -" clip-path="url(#pce7f51428d)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> +" clip-path="url(#p5091658acf)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> @@ -4232,12 +4232,12 @@ L 111.570287 125.513942 L 111.840085 125.514648 L 112.109882 125.515065 L 112.379679 125.515202 -" clip-path="url(#pce7f51428d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5091658acf)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5091658acf)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4255,7 +4255,7 @@ L 141.579832 132.48 L 141.579832 113.844706 L 118.134454 113.844706 z -" clip-path="url(#p919d840972)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> +" clip-path="url(#p62841b35f3)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> @@ -4340,12 +4340,12 @@ L 139.704741 125.520056 L 139.974538 125.517334 L 140.244336 125.515728 L 140.514133 125.515202 -" clip-path="url(#p919d840972)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p62841b35f3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p62841b35f3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4363,7 +4363,7 @@ L 169.714286 132.48 L 169.714286 113.844706 L 146.268908 113.844706 z -" clip-path="url(#pb15abc7d5c)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#pacf570fd14)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -4448,12 +4448,12 @@ L 167.839195 125.514499 L 168.108992 125.514893 L 168.378789 125.515125 L 168.648587 125.515202 -" clip-path="url(#pb15abc7d5c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pacf570fd14)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pacf570fd14)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4471,7 +4471,7 @@ L 197.848739 132.48 L 197.848739 113.844706 L 174.403361 113.844706 z -" clip-path="url(#pbd9f680977)" style="fill: #fffdfd; opacity: 0.5; stroke: #fffdfd; stroke-linejoin: miter"/> +" clip-path="url(#pc8b718a783)" style="fill: #fffdfd; opacity: 0.5; stroke: #fffdfd; stroke-linejoin: miter"/> @@ -4556,12 +4556,12 @@ L 195.973649 125.522113 L 196.243446 125.518237 L 196.513243 125.515951 L 196.78304 125.515202 -" clip-path="url(#pbd9f680977)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc8b718a783)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc8b718a783)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4579,7 +4579,7 @@ L 225.983193 132.48 L 225.983193 113.844706 L 202.537815 113.844706 z -" clip-path="url(#p1643e33e10)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> +" clip-path="url(#pd356931e50)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> @@ -4664,12 +4664,12 @@ L 224.108103 125.512703 L 224.3779 125.514104 L 224.647697 125.514931 L 224.917494 125.515202 -" clip-path="url(#p1643e33e10)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd356931e50)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd356931e50)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4687,7 +4687,7 @@ L 254.117647 132.48 L 254.117647 113.844706 L 230.672269 113.844706 z -" clip-path="url(#pf40ff6d0e7)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> +" clip-path="url(#pcf8182eb19)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> @@ -4772,12 +4772,12 @@ L 252.242556 125.524869 L 252.512354 125.519447 L 252.782151 125.51625 L 253.051948 125.515202 -" clip-path="url(#pf40ff6d0e7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcf8182eb19)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcf8182eb19)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4795,7 +4795,7 @@ L 282.252101 132.48 L 282.252101 113.844706 L 258.806723 113.844706 z -" clip-path="url(#pc49e2dd58b)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> +" clip-path="url(#p3ef6137bdf)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> @@ -4880,12 +4880,12 @@ L 280.37701 125.520904 L 280.646807 125.517706 L 280.916605 125.51582 L 281.186402 125.515202 -" clip-path="url(#pc49e2dd58b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3ef6137bdf)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3ef6137bdf)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -4903,7 +4903,7 @@ L 310.386555 132.48 L 310.386555 113.844706 L 286.941176 113.844706 z -" clip-path="url(#pe9ba0adafe)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> +" clip-path="url(#pf5ed86272e)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> @@ -4988,12 +4988,12 @@ L 308.511464 125.516419 L 308.781261 125.515736 L 309.051058 125.515334 L 309.320856 125.515202 -" clip-path="url(#pe9ba0adafe)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf5ed86272e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf5ed86272e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5011,7 +5011,7 @@ L 338.521008 132.48 L 338.521008 113.844706 L 315.07563 113.844706 z -" clip-path="url(#pfdcc28bb2a)" style="fill: #9595ff; opacity: 0.5; stroke: #9595ff; stroke-linejoin: miter"/> +" clip-path="url(#p57847b349c)" style="fill: #9595ff; opacity: 0.5; stroke: #9595ff; stroke-linejoin: miter"/> @@ -5096,12 +5096,12 @@ L 336.645918 125.518916 L 336.915715 125.516833 L 337.185512 125.515604 L 337.455309 125.515202 -" clip-path="url(#pfdcc28bb2a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p57847b349c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p57847b349c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5119,7 +5119,7 @@ L 366.655462 132.48 L 366.655462 113.844706 L 343.210084 113.844706 z -" clip-path="url(#pd552e9b60a)" style="fill: #5959ff; opacity: 0.5; stroke: #5959ff; stroke-linejoin: miter"/> +" clip-path="url(#pe443beb073)" style="fill: #5959ff; opacity: 0.5; stroke: #5959ff; stroke-linejoin: miter"/> @@ -5204,12 +5204,12 @@ L 364.780372 125.522911 L 365.050169 125.518588 L 365.319966 125.516038 L 365.589763 125.515202 -" clip-path="url(#pd552e9b60a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe443beb073)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe443beb073)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5227,7 +5227,7 @@ L 394.789916 132.48 L 394.789916 113.844706 L 371.344538 113.844706 z -" clip-path="url(#p00eb151a02)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> +" clip-path="url(#p94681e0b45)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> @@ -5312,12 +5312,12 @@ L 392.914825 125.515675 L 393.184623 125.515409 L 393.45442 125.515253 L 393.724217 125.515202 -" clip-path="url(#p00eb151a02)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p94681e0b45)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p94681e0b45)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5335,7 +5335,7 @@ L 422.92437 132.48 L 422.92437 113.844706 L 399.478992 113.844706 z -" clip-path="url(#pbd79e5699e)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> +" clip-path="url(#p235daef786)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> @@ -5420,12 +5420,12 @@ L 421.049279 125.509866 L 421.319076 125.512858 L 421.588874 125.514623 L 421.858671 125.515202 -" clip-path="url(#pbd79e5699e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p235daef786)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p235daef786)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5443,7 +5443,7 @@ L 451.058824 132.48 L 451.058824 113.844706 L 427.613445 113.844706 z -" clip-path="url(#p2f5bc6f690)" style="fill: #3535ff; opacity: 0.5; stroke: #3535ff; stroke-linejoin: miter"/> +" clip-path="url(#p6cc860defb)" style="fill: #3535ff; opacity: 0.5; stroke: #3535ff; stroke-linejoin: miter"/> @@ -5528,12 +5528,12 @@ L 449.183733 125.529886 L 449.45353 125.521651 L 449.723327 125.516795 L 449.993125 125.515202 -" clip-path="url(#p2f5bc6f690)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6cc860defb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6cc860defb)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5551,7 +5551,7 @@ L 479.193277 132.48 L 479.193277 113.844706 L 455.747899 113.844706 z -" clip-path="url(#pf9452764f3)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> +" clip-path="url(#p8bbec0c3dd)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> @@ -5636,12 +5636,12 @@ L 477.318187 125.518861 L 477.587984 125.516809 L 477.857781 125.515598 L 478.127578 125.515202 -" clip-path="url(#pf9452764f3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8bbec0c3dd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8bbec0c3dd)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5659,7 +5659,7 @@ L 507.327731 132.48 L 507.327731 113.844706 L 483.882353 113.844706 z -" clip-path="url(#p6fe904d702)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> +" clip-path="url(#p9a04fd3522)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> @@ -5744,12 +5744,12 @@ L 505.45264 125.51748 L 505.722438 125.516202 L 505.992235 125.515449 L 506.262032 125.515202 -" clip-path="url(#p6fe904d702)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9a04fd3522)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9a04fd3522)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5767,7 +5767,7 @@ L 535.462185 132.48 L 535.462185 113.844706 L 512.016807 113.844706 z -" clip-path="url(#p72501c00b0)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> +" clip-path="url(#p38c57b802f)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> @@ -5852,12 +5852,12 @@ L 533.587094 125.511616 L 533.856891 125.513627 L 534.126689 125.514813 L 534.396486 125.515202 -" clip-path="url(#p72501c00b0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p38c57b802f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p38c57b802f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5875,7 +5875,7 @@ L 563.596639 132.48 L 563.596639 113.844706 L 540.151261 113.844706 z -" clip-path="url(#pa9869eebb9)" style="fill: #ddddff; opacity: 0.5; stroke: #ddddff; stroke-linejoin: miter"/> +" clip-path="url(#p94b6ef7b06)" style="fill: #ddddff; opacity: 0.5; stroke: #ddddff; stroke-linejoin: miter"/> @@ -5960,12 +5960,12 @@ L 561.721548 125.511292 L 561.991345 125.513484 L 562.261142 125.514777 L 562.53094 125.515202 -" clip-path="url(#pa9869eebb9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p94b6ef7b06)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p94b6ef7b06)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -5983,7 +5983,7 @@ L 591.731092 132.48 L 591.731092 113.844706 L 568.285714 113.844706 z -" clip-path="url(#p854651f5fe)" style="fill: #3939ff; opacity: 0.5; stroke: #3939ff; stroke-linejoin: miter"/> +" clip-path="url(#paa103e1bc8)" style="fill: #3939ff; opacity: 0.5; stroke: #3939ff; stroke-linejoin: miter"/> @@ -6068,12 +6068,12 @@ L 589.856002 125.532233 L 590.125799 125.522682 L 590.395596 125.517049 L 590.665393 125.515202 -" clip-path="url(#p854651f5fe)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa103e1bc8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paa103e1bc8)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6091,7 +6091,7 @@ L 619.865546 132.48 L 619.865546 113.844706 L 596.420168 113.844706 z -" clip-path="url(#p40be0f2b81)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> +" clip-path="url(#p11a47dbe06)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> @@ -6176,12 +6176,12 @@ L 617.990456 125.521835 L 618.260253 125.518115 L 618.53005 125.515921 L 618.799847 125.515202 -" clip-path="url(#p40be0f2b81)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p11a47dbe06)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p11a47dbe06)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6199,7 +6199,7 @@ L 113.445378 154.842353 L 113.445378 136.207059 L 90 136.207059 z -" clip-path="url(#p76dc0f3bd0)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> +" clip-path="url(#p69e6e4aac7)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> @@ -6284,12 +6284,12 @@ L 111.570287 145.333485 L 111.840085 145.339008 L 112.109882 145.342264 L 112.379679 145.343333 -" clip-path="url(#p76dc0f3bd0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p69e6e4aac7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p69e6e4aac7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6307,7 +6307,7 @@ L 141.579832 154.842353 L 141.579832 136.207059 L 118.134454 136.207059 z -" clip-path="url(#pa2b0401fba)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> +" clip-path="url(#p07d315f6d1)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> @@ -6392,12 +6392,12 @@ L 139.704741 145.330453 L 139.974538 145.337676 L 140.244336 145.341935 L 140.514133 145.343333 -" clip-path="url(#pa2b0401fba)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p07d315f6d1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p07d315f6d1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6415,7 +6415,7 @@ L 169.714286 154.842353 L 169.714286 136.207059 L 146.268908 136.207059 z -" clip-path="url(#pee2fc5deb4)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> +" clip-path="url(#p002739c16b)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> @@ -6500,12 +6500,12 @@ L 167.839195 145.346775 L 168.108992 145.344845 L 168.378789 145.343706 L 168.648587 145.343333 -" clip-path="url(#pee2fc5deb4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p002739c16b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p002739c16b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6523,7 +6523,7 @@ L 197.848739 154.842353 L 197.848739 136.207059 L 174.403361 136.207059 z -" clip-path="url(#pc847b639a1)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p0ef4cc0e16)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -6608,12 +6608,12 @@ L 195.973649 145.325163 L 196.243446 145.335353 L 196.513243 145.341362 L 196.78304 145.343333 -" clip-path="url(#pc847b639a1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0ef4cc0e16)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0ef4cc0e16)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6631,7 +6631,7 @@ L 225.983193 154.842353 L 225.983193 136.207059 L 202.537815 136.207059 z -" clip-path="url(#pa5c6c4376c)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> +" clip-path="url(#pd0352cbaa0)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> @@ -6716,12 +6716,12 @@ L 224.108103 145.336531 L 224.3779 145.340345 L 224.647697 145.342595 L 224.917494 145.343333 -" clip-path="url(#pa5c6c4376c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd0352cbaa0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd0352cbaa0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6739,7 +6739,7 @@ L 254.117647 154.842353 L 254.117647 136.207059 L 230.672269 136.207059 z -" clip-path="url(#pf042cc27ef)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> +" clip-path="url(#p46eb43ae00)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> @@ -6824,12 +6824,12 @@ L 252.242556 145.354306 L 252.512354 145.348152 L 252.782151 145.344523 L 253.051948 145.343333 -" clip-path="url(#pf042cc27ef)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p46eb43ae00)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p46eb43ae00)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6847,7 +6847,7 @@ L 282.252101 154.842353 L 282.252101 136.207059 L 258.806723 136.207059 z -" clip-path="url(#pea10ea2257)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> +" clip-path="url(#p398f17aefa)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> @@ -6932,12 +6932,12 @@ L 280.37701 145.360615 L 280.646807 145.350923 L 280.916605 145.345207 L 281.186402 145.343333 -" clip-path="url(#pea10ea2257)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p398f17aefa)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p398f17aefa)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -6955,7 +6955,7 @@ L 310.386555 154.842353 L 310.386555 136.207059 L 286.941176 136.207059 z -" clip-path="url(#p1faeb4759d)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> +" clip-path="url(#p7289e968a8)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> @@ -7040,12 +7040,12 @@ L 308.511464 145.358301 L 308.781261 145.349907 L 309.051058 145.344956 L 309.320856 145.343333 -" clip-path="url(#p1faeb4759d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7289e968a8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7289e968a8)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7063,7 +7063,7 @@ L 338.521008 154.842353 L 338.521008 136.207059 L 315.07563 136.207059 z -" clip-path="url(#p8f6a2c0a97)" style="fill: #5555ff; opacity: 0.5; stroke: #5555ff; stroke-linejoin: miter"/> +" clip-path="url(#pf82f567ee2)" style="fill: #5555ff; opacity: 0.5; stroke: #5555ff; stroke-linejoin: miter"/> @@ -7148,12 +7148,12 @@ L 336.645918 145.368196 L 336.915715 145.354253 L 337.185512 145.34603 L 337.455309 145.343333 -" clip-path="url(#p8f6a2c0a97)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf82f567ee2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf82f567ee2)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7171,7 +7171,7 @@ L 366.655462 154.842353 L 366.655462 136.207059 L 343.210084 136.207059 z -" clip-path="url(#pdf16cac5ae)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> +" clip-path="url(#pe7aaa00b8b)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> @@ -7256,12 +7256,12 @@ L 364.780372 145.3529 L 365.050169 145.347535 L 365.319966 145.34437 L 365.589763 145.343333 -" clip-path="url(#pdf16cac5ae)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe7aaa00b8b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe7aaa00b8b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7279,7 +7279,7 @@ L 394.789916 154.842353 L 394.789916 136.207059 L 371.344538 136.207059 z -" clip-path="url(#pd800546816)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#p3e07066afe)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -7364,12 +7364,12 @@ L 392.914825 145.348299 L 393.184623 145.345514 L 393.45442 145.343871 L 393.724217 145.343333 -" clip-path="url(#pd800546816)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3e07066afe)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3e07066afe)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7387,7 +7387,7 @@ L 422.92437 154.842353 L 422.92437 136.207059 L 399.478992 136.207059 z -" clip-path="url(#p677fe0f90b)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> +" clip-path="url(#p010f98991e)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> @@ -7472,12 +7472,12 @@ L 421.049279 145.344643 L 421.319076 145.343908 L 421.588874 145.343475 L 421.858671 145.343333 -" clip-path="url(#p677fe0f90b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p010f98991e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p010f98991e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7495,7 +7495,7 @@ L 451.058824 154.842353 L 451.058824 136.207059 L 427.613445 136.207059 z -" clip-path="url(#p28e2c629f7)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> +" clip-path="url(#p9d436a4aba)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> @@ -7580,12 +7580,12 @@ L 449.183733 145.348759 L 449.45353 145.345716 L 449.723327 145.343921 L 449.993125 145.343333 -" clip-path="url(#p28e2c629f7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9d436a4aba)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9d436a4aba)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7603,7 +7603,7 @@ L 479.193277 154.842353 L 479.193277 136.207059 L 455.747899 136.207059 z -" clip-path="url(#p2d28fb7b9b)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> +" clip-path="url(#p1a7939b3ad)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> @@ -7688,12 +7688,12 @@ L 477.318187 145.332951 L 477.587984 145.338773 L 477.857781 145.342206 L 478.127578 145.343333 -" clip-path="url(#p2d28fb7b9b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1a7939b3ad)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1a7939b3ad)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7711,7 +7711,7 @@ L 507.327731 154.842353 L 507.327731 136.207059 L 483.882353 136.207059 z -" clip-path="url(#pc3e7479958)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#p270fcf1378)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -7796,12 +7796,12 @@ L 505.45264 145.344208 L 505.722438 145.343717 L 505.992235 145.343428 L 506.262032 145.343333 -" clip-path="url(#pc3e7479958)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p270fcf1378)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p270fcf1378)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7819,7 +7819,7 @@ L 535.462185 154.842353 L 535.462185 136.207059 L 512.016807 136.207059 z -" clip-path="url(#pbe3033c7de)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#pf511766562)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -7904,12 +7904,12 @@ L 533.587094 145.342733 L 533.856891 145.343069 L 534.126689 145.343268 L 534.396486 145.343333 -" clip-path="url(#pbe3033c7de)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf511766562)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf511766562)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -7927,7 +7927,7 @@ L 563.596639 154.842353 L 563.596639 136.207059 L 540.151261 136.207059 z -" clip-path="url(#pe7f1885902)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> +" clip-path="url(#pf25c183b2a)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> @@ -8012,12 +8012,12 @@ L 561.721548 145.353708 L 561.991345 145.347889 L 562.261142 145.344458 L 562.53094 145.343333 -" clip-path="url(#pe7f1885902)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf25c183b2a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf25c183b2a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8035,7 +8035,7 @@ L 591.731092 154.842353 L 591.731092 136.207059 L 568.285714 136.207059 z -" clip-path="url(#pdf5344ba22)" style="fill: #4141ff; opacity: 0.5; stroke: #4141ff; stroke-linejoin: miter"/> +" clip-path="url(#p0f49d0ec73)" style="fill: #4141ff; opacity: 0.5; stroke: #4141ff; stroke-linejoin: miter"/> @@ -8120,12 +8120,12 @@ L 589.856002 145.365246 L 590.125799 145.352957 L 590.395596 145.34571 L 590.665393 145.343333 -" clip-path="url(#pdf5344ba22)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0f49d0ec73)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0f49d0ec73)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8143,7 +8143,7 @@ L 619.865546 154.842353 L 619.865546 136.207059 L 596.420168 136.207059 z -" clip-path="url(#pedd277f254)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> +" clip-path="url(#p2600f660fe)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> @@ -8228,12 +8228,12 @@ L 617.990456 145.350949 L 618.260253 145.346678 L 618.53005 145.344159 L 618.799847 145.343333 -" clip-path="url(#pedd277f254)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2600f660fe)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2600f660fe)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8251,7 +8251,7 @@ L 113.445378 177.204706 L 113.445378 158.569412 L 90 158.569412 z -" clip-path="url(#p3006782477)" style="fill: #ffd1d1; opacity: 0.5; stroke: #ffd1d1; stroke-linejoin: miter"/> +" clip-path="url(#p482c37f4e6)" style="fill: #ffd1d1; opacity: 0.5; stroke: #ffd1d1; stroke-linejoin: miter"/> @@ -8336,12 +8336,12 @@ L 111.570287 167.339939 L 111.840085 167.339927 L 112.109882 167.33992 L 112.379679 167.339918 -" clip-path="url(#p3006782477)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p482c37f4e6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p482c37f4e6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8359,7 +8359,7 @@ L 141.579832 177.204706 L 141.579832 158.569412 L 118.134454 158.569412 z -" clip-path="url(#p33f9acf7ff)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> +" clip-path="url(#pfd193104fc)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> @@ -8444,12 +8444,12 @@ L 139.704741 167.340277 L 139.974538 167.340076 L 140.244336 167.339957 L 140.514133 167.339918 -" clip-path="url(#p33f9acf7ff)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfd193104fc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfd193104fc)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8467,7 +8467,7 @@ L 169.714286 177.204706 L 169.714286 158.569412 L 146.268908 158.569412 z -" clip-path="url(#p064a14cc9f)" style="fill: #ffb1b1; opacity: 0.5; stroke: #ffb1b1; stroke-linejoin: miter"/> +" clip-path="url(#p8be689e7cb)" style="fill: #ffb1b1; opacity: 0.5; stroke: #ffb1b1; stroke-linejoin: miter"/> @@ -8552,12 +8552,12 @@ L 167.839195 167.34262 L 168.108992 167.341105 L 168.378789 167.340211 L 168.648587 167.339918 -" clip-path="url(#p064a14cc9f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8be689e7cb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8be689e7cb)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8575,7 +8575,7 @@ L 197.848739 177.204706 L 197.848739 158.569412 L 174.403361 158.569412 z -" clip-path="url(#p788155f36e)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> +" clip-path="url(#pef59352fcc)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> @@ -8660,12 +8660,12 @@ L 195.973649 167.332598 L 196.243446 167.336703 L 196.513243 167.339124 L 196.78304 167.339918 -" clip-path="url(#p788155f36e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pef59352fcc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pef59352fcc)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8683,7 +8683,7 @@ L 225.983193 177.204706 L 225.983193 158.569412 L 202.537815 158.569412 z -" clip-path="url(#pfeef4429b9)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#pa7ad7b559f)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -8768,12 +8768,12 @@ L 224.108103 167.332915 L 224.3779 167.336842 L 224.647697 167.339158 L 224.917494 167.339918 -" clip-path="url(#pfeef4429b9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa7ad7b559f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa7ad7b559f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8791,7 +8791,7 @@ L 254.117647 177.204706 L 254.117647 158.569412 L 230.672269 158.569412 z -" clip-path="url(#p1a2dbf897e)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> +" clip-path="url(#p62441b451d)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> @@ -8876,12 +8876,12 @@ L 252.242556 167.340242 L 252.512354 167.34006 L 252.782151 167.339953 L 253.051948 167.339918 -" clip-path="url(#p1a2dbf897e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p62441b451d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p62441b451d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -8899,7 +8899,7 @@ L 282.252101 177.204706 L 282.252101 158.569412 L 258.806723 158.569412 z -" clip-path="url(#pc2db60778b)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> +" clip-path="url(#p5eff30f189)" style="fill: #ffe1e1; opacity: 0.5; stroke: #ffe1e1; stroke-linejoin: miter"/> @@ -8984,12 +8984,12 @@ L 280.37701 167.338628 L 280.646807 167.339351 L 280.916605 167.339778 L 281.186402 167.339918 -" clip-path="url(#pc2db60778b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5eff30f189)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5eff30f189)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9007,7 +9007,7 @@ L 310.386555 177.204706 L 310.386555 158.569412 L 286.941176 158.569412 z -" clip-path="url(#p7913d3c78a)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> +" clip-path="url(#p8824ee2dce)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> @@ -9092,12 +9092,12 @@ L 308.511464 167.335093 L 308.781261 167.337799 L 309.051058 167.339395 L 309.320856 167.339918 -" clip-path="url(#p7913d3c78a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8824ee2dce)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8824ee2dce)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9115,7 +9115,7 @@ L 338.521008 177.204706 L 338.521008 158.569412 L 315.07563 158.569412 z -" clip-path="url(#p904c3a0284)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> +" clip-path="url(#pd8fae228c3)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> @@ -9200,12 +9200,12 @@ L 336.645918 167.343142 L 336.915715 167.341334 L 337.185512 167.340268 L 337.455309 167.339918 -" clip-path="url(#p904c3a0284)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd8fae228c3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd8fae228c3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9223,7 +9223,7 @@ L 366.655462 177.204706 L 366.655462 158.569412 L 343.210084 158.569412 z -" clip-path="url(#p178b8b3166)" style="fill: #6565ff; opacity: 0.5; stroke: #6565ff; stroke-linejoin: miter"/> +" clip-path="url(#pcf37eaab4a)" style="fill: #6565ff; opacity: 0.5; stroke: #6565ff; stroke-linejoin: miter"/> @@ -9308,12 +9308,12 @@ L 364.780372 167.349718 L 365.050169 167.344222 L 365.319966 167.340981 L 365.589763 167.339918 -" clip-path="url(#p178b8b3166)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcf37eaab4a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcf37eaab4a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9331,7 +9331,7 @@ L 394.789916 177.204706 L 394.789916 158.569412 L 371.344538 158.569412 z -" clip-path="url(#pfdcd416727)" style="fill: #a9a9ff; opacity: 0.5; stroke: #a9a9ff; stroke-linejoin: miter"/> +" clip-path="url(#p762e06f26d)" style="fill: #a9a9ff; opacity: 0.5; stroke: #a9a9ff; stroke-linejoin: miter"/> @@ -9416,12 +9416,12 @@ L 392.914825 167.341655 L 393.184623 167.340681 L 393.45442 167.340106 L 393.724217 167.339918 -" clip-path="url(#pfdcd416727)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p762e06f26d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p762e06f26d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9439,7 +9439,7 @@ L 422.92437 177.204706 L 422.92437 158.569412 L 399.478992 158.569412 z -" clip-path="url(#p42a85e3edd)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> +" clip-path="url(#p87e97aa821)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> @@ -9524,12 +9524,12 @@ L 421.049279 167.354294 L 421.319076 167.346232 L 421.588874 167.341478 L 421.858671 167.339918 -" clip-path="url(#p42a85e3edd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p87e97aa821)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p87e97aa821)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9547,7 +9547,7 @@ L 451.058824 177.204706 L 451.058824 158.569412 L 427.613445 158.569412 z -" clip-path="url(#p01b40a8f61)" style="fill: #0000f7; opacity: 0.5; stroke: #0000f7; stroke-linejoin: miter"/> +" clip-path="url(#pb23755a223)" style="fill: #0000f7; opacity: 0.5; stroke: #0000f7; stroke-linejoin: miter"/> @@ -9632,12 +9632,12 @@ L 449.183733 167.3586 L 449.45353 167.348123 L 449.723327 167.341945 L 449.993125 167.339918 -" clip-path="url(#p01b40a8f61)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb23755a223)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb23755a223)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9655,7 +9655,7 @@ L 479.193277 177.204706 L 479.193277 158.569412 L 455.747899 158.569412 z -" clip-path="url(#p923f3e33e8)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> +" clip-path="url(#pd2f01610d0)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> @@ -9740,12 +9740,12 @@ L 477.318187 167.349211 L 477.587984 167.344 L 477.857781 167.340926 L 478.127578 167.339918 -" clip-path="url(#p923f3e33e8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd2f01610d0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd2f01610d0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9763,7 +9763,7 @@ L 507.327731 177.204706 L 507.327731 158.569412 L 483.882353 158.569412 z -" clip-path="url(#p2b102c0960)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> +" clip-path="url(#pa7aaa65ea9)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> @@ -9848,12 +9848,12 @@ L 505.45264 167.335842 L 505.722438 167.338128 L 505.992235 167.339476 L 506.262032 167.339918 -" clip-path="url(#p2b102c0960)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa7aaa65ea9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa7aaa65ea9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9871,7 +9871,7 @@ L 535.462185 177.204706 L 535.462185 158.569412 L 512.016807 158.569412 z -" clip-path="url(#pf040a10fd5)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> +" clip-path="url(#p50c8e9d8ea)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> @@ -9956,12 +9956,12 @@ L 533.587094 167.340062 L 533.856891 167.339981 L 534.126689 167.339934 L 534.396486 167.339918 -" clip-path="url(#pf040a10fd5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p50c8e9d8ea)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p50c8e9d8ea)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -9979,7 +9979,7 @@ L 563.596639 177.204706 L 563.596639 158.569412 L 540.151261 158.569412 z -" clip-path="url(#pb5b606a2d0)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#pdee213bd2b)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -10064,12 +10064,12 @@ L 561.721548 167.336189 L 561.991345 167.33828 L 562.261142 167.339513 L 562.53094 167.339918 -" clip-path="url(#pb5b606a2d0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdee213bd2b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdee213bd2b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10087,7 +10087,7 @@ L 591.731092 177.204706 L 591.731092 158.569412 L 568.285714 158.569412 z -" clip-path="url(#p6561dba3ea)" style="fill: #1515ff; opacity: 0.5; stroke: #1515ff; stroke-linejoin: miter"/> +" clip-path="url(#p47b07a871c)" style="fill: #1515ff; opacity: 0.5; stroke: #1515ff; stroke-linejoin: miter"/> @@ -10172,12 +10172,12 @@ L 589.856002 167.355758 L 590.125799 167.346875 L 590.395596 167.341636 L 590.665393 167.339918 -" clip-path="url(#p6561dba3ea)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p47b07a871c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p47b07a871c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10195,7 +10195,7 @@ L 619.865546 177.204706 L 619.865546 158.569412 L 596.420168 158.569412 z -" clip-path="url(#pa70a23ed0f)" style="fill: #6d6dff; opacity: 0.5; stroke: #6d6dff; stroke-linejoin: miter"/> +" clip-path="url(#p6908328e47)" style="fill: #6d6dff; opacity: 0.5; stroke: #6d6dff; stroke-linejoin: miter"/> @@ -10280,12 +10280,12 @@ L 617.990456 167.349142 L 618.260253 167.343969 L 618.53005 167.340919 L 618.799847 167.339918 -" clip-path="url(#pa70a23ed0f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6908328e47)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6908328e47)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10303,7 +10303,7 @@ L 113.445378 199.567059 L 113.445378 180.931765 L 90 180.931765 z -" clip-path="url(#p3dc3d457f1)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#pe7c354f935)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -10388,12 +10388,12 @@ L 111.570287 191.985482 L 111.840085 191.985884 L 112.109882 191.986121 L 112.379679 191.986199 -" clip-path="url(#p3dc3d457f1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe7c354f935)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe7c354f935)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10411,7 +10411,7 @@ L 141.579832 199.567059 L 141.579832 180.931765 L 118.134454 180.931765 z -" clip-path="url(#pc4903c3fca)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> +" clip-path="url(#p287e4228af)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> @@ -10496,12 +10496,12 @@ L 139.704741 191.977935 L 139.974538 191.982569 L 140.244336 191.985303 L 140.514133 191.986199 -" clip-path="url(#pc4903c3fca)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p287e4228af)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p287e4228af)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10519,7 +10519,7 @@ L 169.714286 199.567059 L 169.714286 180.931765 L 146.268908 180.931765 z -" clip-path="url(#p819679df4a)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#pc6723b7b59)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -10604,12 +10604,12 @@ L 167.839195 191.995921 L 168.108992 191.990469 L 168.378789 191.987254 L 168.648587 191.986199 -" clip-path="url(#p819679df4a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc6723b7b59)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc6723b7b59)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10627,7 +10627,7 @@ L 197.848739 199.567059 L 197.848739 180.931765 L 174.403361 180.931765 z -" clip-path="url(#p93585ebcbc)" style="fill: #ffc9c9; opacity: 0.5; stroke: #ffc9c9; stroke-linejoin: miter"/> +" clip-path="url(#p9922dfa49a)" style="fill: #ffc9c9; opacity: 0.5; stroke: #ffc9c9; stroke-linejoin: miter"/> @@ -10712,12 +10712,12 @@ L 195.973649 191.977862 L 196.243446 191.982537 L 196.513243 191.985295 L 196.78304 191.986199 -" clip-path="url(#p93585ebcbc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9922dfa49a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9922dfa49a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10735,7 +10735,7 @@ L 225.983193 199.567059 L 225.983193 180.931765 L 202.537815 180.931765 z -" clip-path="url(#pa376a79194)" style="fill: #ffc5c5; opacity: 0.5; stroke: #ffc5c5; stroke-linejoin: miter"/> +" clip-path="url(#p1b57af7854)" style="fill: #ffc5c5; opacity: 0.5; stroke: #ffc5c5; stroke-linejoin: miter"/> @@ -10820,12 +10820,12 @@ L 224.108103 191.979412 L 224.3779 191.983218 L 224.647697 191.985463 L 224.917494 191.986199 -" clip-path="url(#pa376a79194)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1b57af7854)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1b57af7854)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10843,7 +10843,7 @@ L 254.117647 199.567059 L 254.117647 180.931765 L 230.672269 180.931765 z -" clip-path="url(#p07f3762b20)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#pf72070ab50)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -10928,12 +10928,12 @@ L 252.242556 191.965628 L 252.512354 191.977164 L 252.782151 191.983967 L 253.051948 191.986199 -" clip-path="url(#p07f3762b20)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf72070ab50)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf72070ab50)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -10951,7 +10951,7 @@ L 282.252101 199.567059 L 282.252101 180.931765 L 258.806723 180.931765 z -" clip-path="url(#pcbc52a6c18)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> +" clip-path="url(#p1fcbfd876a)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> @@ -11036,12 +11036,12 @@ L 280.37701 191.987483 L 280.646807 191.986763 L 280.916605 191.986338 L 281.186402 191.986199 -" clip-path="url(#pcbc52a6c18)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1fcbfd876a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1fcbfd876a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11059,7 +11059,7 @@ L 310.386555 199.567059 L 310.386555 180.931765 L 286.941176 180.931765 z -" clip-path="url(#p9b6750bd04)" style="fill: #ffc9c9; opacity: 0.5; stroke: #ffc9c9; stroke-linejoin: miter"/> +" clip-path="url(#p43eb8918cc)" style="fill: #ffc9c9; opacity: 0.5; stroke: #ffc9c9; stroke-linejoin: miter"/> @@ -11144,12 +11144,12 @@ L 308.511464 191.979301 L 308.781261 191.983169 L 309.051058 191.985451 L 309.320856 191.986199 -" clip-path="url(#p9b6750bd04)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p43eb8918cc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p43eb8918cc)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11167,7 +11167,7 @@ L 338.521008 199.567059 L 338.521008 180.931765 L 315.07563 180.931765 z -" clip-path="url(#pe0e6dc86e2)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> +" clip-path="url(#p817f920115)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> @@ -11252,12 +11252,12 @@ L 336.645918 191.975553 L 336.915715 191.981523 L 337.185512 191.985044 L 337.455309 191.986199 -" clip-path="url(#pe0e6dc86e2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p817f920115)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p817f920115)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11275,7 +11275,7 @@ L 366.655462 199.567059 L 366.655462 180.931765 L 343.210084 180.931765 z -" clip-path="url(#p04c17d9da9)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> +" clip-path="url(#p7d323e8143)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> @@ -11360,12 +11360,12 @@ L 364.780372 191.98442 L 365.050169 191.985418 L 365.319966 191.986006 L 365.589763 191.986199 -" clip-path="url(#p04c17d9da9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7d323e8143)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7d323e8143)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11383,7 +11383,7 @@ L 394.789916 199.567059 L 394.789916 180.931765 L 371.344538 180.931765 z -" clip-path="url(#pc416a7a754)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> +" clip-path="url(#p8ac8414c19)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> @@ -11468,12 +11468,12 @@ L 392.914825 191.985499 L 393.184623 191.985892 L 393.45442 191.986123 L 393.724217 191.986199 -" clip-path="url(#pc416a7a754)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ac8414c19)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8ac8414c19)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11491,7 +11491,7 @@ L 422.92437 199.567059 L 422.92437 180.931765 L 399.478992 180.931765 z -" clip-path="url(#p2dd7175ad4)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#p6737b7db78)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -11576,12 +11576,12 @@ L 421.049279 191.995518 L 421.319076 191.990292 L 421.588874 191.98721 L 421.858671 191.986199 -" clip-path="url(#p2dd7175ad4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6737b7db78)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6737b7db78)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11599,7 +11599,7 @@ L 451.058824 199.567059 L 451.058824 180.931765 L 427.613445 180.931765 z -" clip-path="url(#pd6321d5c96)" style="fill: #8585ff; opacity: 0.5; stroke: #8585ff; stroke-linejoin: miter"/> +" clip-path="url(#pe41f08ee8b)" style="fill: #8585ff; opacity: 0.5; stroke: #8585ff; stroke-linejoin: miter"/> @@ -11684,12 +11684,12 @@ L 449.183733 192.007995 L 449.45353 191.995772 L 449.723327 191.988564 L 449.993125 191.986199 -" clip-path="url(#pd6321d5c96)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe41f08ee8b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe41f08ee8b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11707,7 +11707,7 @@ L 479.193277 199.567059 L 479.193277 180.931765 L 455.747899 180.931765 z -" clip-path="url(#p58796f2329)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> +" clip-path="url(#p7c340803ff)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> @@ -11792,12 +11792,12 @@ L 477.318187 191.990027 L 477.587984 191.98788 L 477.857781 191.986614 L 478.127578 191.986199 -" clip-path="url(#p58796f2329)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7c340803ff)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7c340803ff)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11815,7 +11815,7 @@ L 507.327731 199.567059 L 507.327731 180.931765 L 483.882353 180.931765 z -" clip-path="url(#p834822b5b9)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> +" clip-path="url(#p801c343d68)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> @@ -11900,12 +11900,12 @@ L 505.45264 191.990307 L 505.722438 191.988003 L 505.992235 191.986645 L 506.262032 191.986199 -" clip-path="url(#p834822b5b9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p801c343d68)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p801c343d68)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -11923,7 +11923,7 @@ L 535.462185 199.567059 L 535.462185 180.931765 L 512.016807 180.931765 z -" clip-path="url(#p66d14883ed)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#pca1019535c)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -12008,12 +12008,12 @@ L 533.587094 191.988366 L 533.856891 191.987151 L 534.126689 191.986434 L 534.396486 191.986199 -" clip-path="url(#p66d14883ed)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pca1019535c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pca1019535c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12031,7 +12031,7 @@ L 563.596639 199.567059 L 563.596639 180.931765 L 540.151261 180.931765 z -" clip-path="url(#p4872bc1f11)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> +" clip-path="url(#pb820d1d63f)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> @@ -12116,12 +12116,12 @@ L 561.721548 191.996121 L 561.991345 191.990557 L 562.261142 191.987275 L 562.53094 191.986199 -" clip-path="url(#p4872bc1f11)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb820d1d63f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb820d1d63f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12139,7 +12139,7 @@ L 591.731092 199.567059 L 591.731092 180.931765 L 568.285714 180.931765 z -" clip-path="url(#pc1a98399b4)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> +" clip-path="url(#pa3f6a0172c)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> @@ -12224,12 +12224,12 @@ L 589.856002 192.003652 L 590.125799 191.993864 L 590.395596 191.988092 L 590.665393 191.986199 -" clip-path="url(#pc1a98399b4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa3f6a0172c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa3f6a0172c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12247,7 +12247,7 @@ L 619.865546 199.567059 L 619.865546 180.931765 L 596.420168 180.931765 z -" clip-path="url(#p55ce8212df)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#pdc34bf66d5)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -12332,12 +12332,12 @@ L 617.990456 191.994312 L 618.260253 191.989762 L 618.53005 191.987079 L 618.799847 191.986199 -" clip-path="url(#p55ce8212df)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdc34bf66d5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdc34bf66d5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12355,7 +12355,7 @@ L 113.445378 221.929412 L 113.445378 203.294118 L 90 203.294118 z -" clip-path="url(#pebadf450d2)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> +" clip-path="url(#p0d83f5c5a4)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> @@ -12440,12 +12440,12 @@ L 111.570287 213.456812 L 111.840085 213.453205 L 112.109882 213.451078 L 112.379679 213.45038 -" clip-path="url(#pebadf450d2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0d83f5c5a4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0d83f5c5a4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12463,7 +12463,7 @@ L 141.579832 221.929412 L 141.579832 203.294118 L 118.134454 203.294118 z -" clip-path="url(#p8ee54dda3d)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> +" clip-path="url(#pd5350550f7)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> @@ -12548,12 +12548,12 @@ L 139.704741 213.464813 L 139.974538 213.456719 L 140.244336 213.451946 L 140.514133 213.45038 -" clip-path="url(#p8ee54dda3d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd5350550f7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd5350550f7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12571,7 +12571,7 @@ L 169.714286 221.929412 L 169.714286 203.294118 L 146.268908 203.294118 z -" clip-path="url(#pe696cf36d6)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> +" clip-path="url(#pad8880b570)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> @@ -12656,12 +12656,12 @@ L 167.839195 213.468619 L 168.108992 213.458391 L 168.378789 213.452359 L 168.648587 213.45038 -" clip-path="url(#pe696cf36d6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pad8880b570)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pad8880b570)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12679,7 +12679,7 @@ L 197.848739 221.929412 L 197.848739 203.294118 L 174.403361 203.294118 z -" clip-path="url(#pf834bcecf6)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> +" clip-path="url(#p538e072af7)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> @@ -12764,12 +12764,12 @@ L 195.973649 213.454131 L 196.243446 213.452027 L 196.513243 213.450787 L 196.78304 213.45038 -" clip-path="url(#pf834bcecf6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p538e072af7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p538e072af7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12787,7 +12787,7 @@ L 225.983193 221.929412 L 225.983193 203.294118 L 202.537815 203.294118 z -" clip-path="url(#pda83dc9edb)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> +" clip-path="url(#p3369f25db4)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> @@ -12872,12 +12872,12 @@ L 224.108103 213.434237 L 224.3779 213.44329 L 224.647697 213.448629 L 224.917494 213.45038 -" clip-path="url(#pda83dc9edb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3369f25db4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3369f25db4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -12895,7 +12895,7 @@ L 254.117647 221.929412 L 254.117647 203.294118 L 230.672269 203.294118 z -" clip-path="url(#pcb0221e300)" style="fill: #ff7979; opacity: 0.5; stroke: #ff7979; stroke-linejoin: miter"/> +" clip-path="url(#p59e886ca51)" style="fill: #ff7979; opacity: 0.5; stroke: #ff7979; stroke-linejoin: miter"/> @@ -12980,12 +12980,12 @@ L 252.242556 213.423828 L 252.512354 213.438718 L 252.782151 213.4475 L 253.051948 213.45038 -" clip-path="url(#pcb0221e300)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p59e886ca51)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p59e886ca51)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13003,7 +13003,7 @@ L 282.252101 221.929412 L 282.252101 203.294118 L 258.806723 203.294118 z -" clip-path="url(#pd72fff589a)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p7862edead3)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -13088,12 +13088,12 @@ L 280.37701 213.420285 L 280.646807 213.437162 L 280.916605 213.447115 L 281.186402 213.45038 -" clip-path="url(#pd72fff589a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7862edead3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7862edead3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13111,7 +13111,7 @@ L 310.386555 221.929412 L 310.386555 203.294118 L 286.941176 203.294118 z -" clip-path="url(#pe7b9e507ca)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> +" clip-path="url(#p4f2013cdd7)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> @@ -13196,12 +13196,12 @@ L 308.511464 213.436931 L 308.781261 213.444473 L 309.051058 213.448921 L 309.320856 213.45038 -" clip-path="url(#pe7b9e507ca)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4f2013cdd7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4f2013cdd7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13219,7 +13219,7 @@ L 338.521008 221.929412 L 338.521008 203.294118 L 315.07563 203.294118 z -" clip-path="url(#pd70db8b0dc)" style="fill: #ff7171; opacity: 0.5; stroke: #ff7171; stroke-linejoin: miter"/> +" clip-path="url(#pbfe9e8f229)" style="fill: #ff7171; opacity: 0.5; stroke: #ff7171; stroke-linejoin: miter"/> @@ -13304,12 +13304,12 @@ L 336.645918 213.421942 L 336.915715 213.43789 L 337.185512 213.447295 L 337.455309 213.45038 -" clip-path="url(#pd70db8b0dc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbfe9e8f229)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbfe9e8f229)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13327,7 +13327,7 @@ L 366.655462 221.929412 L 366.655462 203.294118 L 343.210084 203.294118 z -" clip-path="url(#pbeb2fa0cd4)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> +" clip-path="url(#pb875c1760b)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> @@ -13412,12 +13412,12 @@ L 364.780372 213.455306 L 365.050169 213.452543 L 365.319966 213.450914 L 365.589763 213.45038 -" clip-path="url(#pbeb2fa0cd4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb875c1760b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb875c1760b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13435,7 +13435,7 @@ L 394.789916 221.929412 L 394.789916 203.294118 L 371.344538 203.294118 z -" clip-path="url(#p53239a1130)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> +" clip-path="url(#pc949a6a9d4)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> @@ -13520,12 +13520,12 @@ L 392.914825 213.43368 L 393.184623 213.443045 L 393.45442 213.448568 L 393.724217 213.45038 -" clip-path="url(#p53239a1130)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc949a6a9d4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc949a6a9d4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13543,7 +13543,7 @@ L 422.92437 221.929412 L 422.92437 203.294118 L 399.478992 203.294118 z -" clip-path="url(#p5f416eae9d)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> +" clip-path="url(#p88fa427b9a)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> @@ -13628,12 +13628,12 @@ L 421.049279 213.457534 L 421.319076 213.453522 L 421.588874 213.451156 L 421.858671 213.45038 -" clip-path="url(#p5f416eae9d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p88fa427b9a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p88fa427b9a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13651,7 +13651,7 @@ L 451.058824 221.929412 L 451.058824 203.294118 L 427.613445 203.294118 z -" clip-path="url(#p5b187be363)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p4bf4ae6c72)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -13736,12 +13736,12 @@ L 449.183733 213.447705 L 449.45353 213.449205 L 449.723327 213.45009 L 449.993125 213.45038 -" clip-path="url(#p5b187be363)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4bf4ae6c72)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4bf4ae6c72)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13759,7 +13759,7 @@ L 479.193277 221.929412 L 479.193277 203.294118 L 455.747899 203.294118 z -" clip-path="url(#pcacb69f336)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> +" clip-path="url(#p36e9b41970)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> @@ -13844,12 +13844,12 @@ L 477.318187 213.437091 L 477.587984 213.444543 L 477.857781 213.448938 L 478.127578 213.45038 -" clip-path="url(#pcacb69f336)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p36e9b41970)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p36e9b41970)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13867,7 +13867,7 @@ L 507.327731 221.929412 L 507.327731 203.294118 L 483.882353 203.294118 z -" clip-path="url(#p00510fe8f1)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p008185475a)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -13952,12 +13952,12 @@ L 505.45264 213.45532 L 505.722438 213.45255 L 505.992235 213.450916 L 506.262032 213.45038 -" clip-path="url(#p00510fe8f1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p008185475a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p008185475a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -13975,7 +13975,7 @@ L 535.462185 221.929412 L 535.462185 203.294118 L 512.016807 203.294118 z -" clip-path="url(#p44906ff351)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> +" clip-path="url(#pcce65cb255)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> @@ -14060,12 +14060,12 @@ L 533.587094 213.443344 L 533.856891 213.44729 L 534.126689 213.449617 L 534.396486 213.45038 -" clip-path="url(#p44906ff351)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcce65cb255)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcce65cb255)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14083,7 +14083,7 @@ L 563.596639 221.929412 L 563.596639 203.294118 L 540.151261 203.294118 z -" clip-path="url(#pf8f4518997)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> +" clip-path="url(#pde48c0932d)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> @@ -14168,12 +14168,12 @@ L 561.721548 213.445931 L 561.991345 213.448426 L 562.261142 213.449898 L 562.53094 213.45038 -" clip-path="url(#pf8f4518997)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pde48c0932d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pde48c0932d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14191,7 +14191,7 @@ L 591.731092 221.929412 L 591.731092 203.294118 L 568.285714 203.294118 z -" clip-path="url(#pd56128005f)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> +" clip-path="url(#p881f2e7301)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> @@ -14276,12 +14276,12 @@ L 589.856002 213.476501 L 590.125799 213.461852 L 590.395596 213.453214 L 590.665393 213.45038 -" clip-path="url(#pd56128005f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p881f2e7301)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p881f2e7301)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14299,7 +14299,7 @@ L 619.865546 221.929412 L 619.865546 203.294118 L 596.420168 203.294118 z -" clip-path="url(#p49e554c618)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> +" clip-path="url(#pb831260556)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> @@ -14384,12 +14384,12 @@ L 617.990456 213.464603 L 618.260253 213.456627 L 618.53005 213.451923 L 618.799847 213.45038 -" clip-path="url(#p49e554c618)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb831260556)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb831260556)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14407,7 +14407,7 @@ L 113.445378 244.291765 L 113.445378 225.656471 L 90 225.656471 z -" clip-path="url(#p4deef4c670)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> +" clip-path="url(#pd30630e0a9)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> @@ -14492,12 +14492,12 @@ L 111.570287 236.692764 L 111.840085 236.68187 L 112.109882 236.675446 L 112.379679 236.673339 -" clip-path="url(#p4deef4c670)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd30630e0a9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd30630e0a9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14515,7 +14515,7 @@ L 141.579832 244.291765 L 141.579832 225.656471 L 118.134454 225.656471 z -" clip-path="url(#p6c1f37fb03)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#pcb451c0fa6)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -14600,12 +14600,12 @@ L 139.704741 236.677595 L 139.974538 236.675208 L 140.244336 236.673801 L 140.514133 236.673339 -" clip-path="url(#p6c1f37fb03)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcb451c0fa6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcb451c0fa6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14623,7 +14623,7 @@ L 169.714286 244.291765 L 169.714286 225.656471 L 146.268908 225.656471 z -" clip-path="url(#pde50286969)" style="fill: #adadff; opacity: 0.5; stroke: #adadff; stroke-linejoin: miter"/> +" clip-path="url(#p6352246106)" style="fill: #adadff; opacity: 0.5; stroke: #adadff; stroke-linejoin: miter"/> @@ -14708,12 +14708,12 @@ L 167.839195 236.68623 L 168.108992 236.679001 L 168.378789 236.674737 L 168.648587 236.673339 -" clip-path="url(#pde50286969)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6352246106)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6352246106)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14731,7 +14731,7 @@ L 197.848739 244.291765 L 197.848739 225.656471 L 174.403361 225.656471 z -" clip-path="url(#p8ae0c06f23)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> +" clip-path="url(#pefc504a16f)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> @@ -14816,12 +14816,12 @@ L 195.973649 236.683315 L 196.243446 236.67772 L 196.513243 236.674421 L 196.78304 236.673339 -" clip-path="url(#p8ae0c06f23)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pefc504a16f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pefc504a16f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14839,7 +14839,7 @@ L 225.983193 244.291765 L 225.983193 225.656471 L 202.537815 225.656471 z -" clip-path="url(#p4db18ff7a1)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> +" clip-path="url(#pddc45a7012)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> @@ -14924,12 +14924,12 @@ L 224.108103 236.661119 L 224.3779 236.667972 L 224.647697 236.672013 L 224.917494 236.673339 -" clip-path="url(#p4db18ff7a1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pddc45a7012)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pddc45a7012)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -14947,7 +14947,7 @@ L 254.117647 244.291765 L 254.117647 225.656471 L 230.672269 225.656471 z -" clip-path="url(#p5a6e50e221)" style="fill: #ff8989; opacity: 0.5; stroke: #ff8989; stroke-linejoin: miter"/> +" clip-path="url(#p13cc947abc)" style="fill: #ff8989; opacity: 0.5; stroke: #ff8989; stroke-linejoin: miter"/> @@ -15032,12 +15032,12 @@ L 252.242556 236.645112 L 252.512354 236.660942 L 252.782151 236.670277 L 253.051948 236.673339 -" clip-path="url(#p5a6e50e221)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p13cc947abc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p13cc947abc)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15055,7 +15055,7 @@ L 282.252101 244.291765 L 282.252101 225.656471 L 258.806723 225.656471 z -" clip-path="url(#p53fbf33eeb)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> +" clip-path="url(#p91fe68a5a5)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> @@ -15140,12 +15140,12 @@ L 280.37701 236.659538 L 280.646807 236.667277 L 280.916605 236.671842 L 281.186402 236.673339 -" clip-path="url(#p53fbf33eeb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p91fe68a5a5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p91fe68a5a5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15163,7 +15163,7 @@ L 310.386555 244.291765 L 310.386555 225.656471 L 286.941176 225.656471 z -" clip-path="url(#pf7a269545d)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#pa17dbfcee0)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -15248,12 +15248,12 @@ L 308.511464 236.641078 L 308.781261 236.65917 L 309.051058 236.669839 L 309.320856 236.673339 -" clip-path="url(#pf7a269545d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa17dbfcee0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa17dbfcee0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15271,7 +15271,7 @@ L 338.521008 244.291765 L 338.521008 225.656471 L 315.07563 225.656471 z -" clip-path="url(#p4406b45992)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> +" clip-path="url(#pc4e49350b1)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> @@ -15356,12 +15356,12 @@ L 336.645918 236.652804 L 336.915715 236.66432 L 337.185512 236.671111 L 337.455309 236.673339 -" clip-path="url(#p4406b45992)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc4e49350b1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc4e49350b1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15379,7 +15379,7 @@ L 366.655462 244.291765 L 366.655462 225.656471 L 343.210084 225.656471 z -" clip-path="url(#p321d1dff4b)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> +" clip-path="url(#p8f9738af5e)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> @@ -15464,12 +15464,12 @@ L 364.780372 236.669554 L 365.050169 236.671676 L 365.319966 236.672928 L 365.589763 236.673339 -" clip-path="url(#p321d1dff4b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8f9738af5e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8f9738af5e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15487,7 +15487,7 @@ L 394.789916 244.291765 L 394.789916 225.656471 L 371.344538 225.656471 z -" clip-path="url(#p61814c0ab5)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> +" clip-path="url(#p5eaceab4b4)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> @@ -15572,12 +15572,12 @@ L 392.914825 236.666624 L 393.184623 236.67039 L 393.45442 236.67261 L 393.724217 236.673339 -" clip-path="url(#p61814c0ab5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5eaceab4b4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5eaceab4b4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15595,7 +15595,7 @@ L 422.92437 244.291765 L 422.92437 225.656471 L 399.478992 225.656471 z -" clip-path="url(#p50ebf97e10)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#pb85cef82c3)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -15680,12 +15680,12 @@ L 421.049279 236.671131 L 421.319076 236.672369 L 421.588874 236.673099 L 421.858671 236.673339 -" clip-path="url(#p50ebf97e10)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb85cef82c3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb85cef82c3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15703,7 +15703,7 @@ L 451.058824 244.291765 L 451.058824 225.656471 L 427.613445 225.656471 z -" clip-path="url(#pba83e3944c)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> +" clip-path="url(#p21773f1b99)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> @@ -15788,12 +15788,12 @@ L 449.183733 236.68525 L 449.45353 236.67857 L 449.723327 236.674631 L 449.993125 236.673339 -" clip-path="url(#pba83e3944c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p21773f1b99)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p21773f1b99)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15811,7 +15811,7 @@ L 479.193277 244.291765 L 479.193277 225.656471 L 455.747899 225.656471 z -" clip-path="url(#pef9decf78d)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> +" clip-path="url(#p78afca2cac)" style="fill: #f9f9ff; opacity: 0.5; stroke: #f9f9ff; stroke-linejoin: miter"/> @@ -15896,12 +15896,12 @@ L 477.318187 236.671734 L 477.587984 236.672634 L 477.857781 236.673165 L 478.127578 236.673339 -" clip-path="url(#pef9decf78d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p78afca2cac)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p78afca2cac)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -15919,7 +15919,7 @@ L 507.327731 244.291765 L 507.327731 225.656471 L 483.882353 225.656471 z -" clip-path="url(#p86fbeef7d1)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> +" clip-path="url(#p84e47c7de4)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> @@ -16004,12 +16004,12 @@ L 505.45264 236.678984 L 505.722438 236.675818 L 505.992235 236.673951 L 506.262032 236.673339 -" clip-path="url(#p86fbeef7d1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p84e47c7de4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p84e47c7de4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16027,7 +16027,7 @@ L 535.462185 244.291765 L 535.462185 225.656471 L 512.016807 225.656471 z -" clip-path="url(#pb1d2c54a53)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> +" clip-path="url(#pd60eac7f9c)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> @@ -16112,12 +16112,12 @@ L 533.587094 236.664773 L 533.856891 236.669577 L 534.126689 236.67241 L 534.396486 236.673339 -" clip-path="url(#pb1d2c54a53)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd60eac7f9c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd60eac7f9c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16135,7 +16135,7 @@ L 563.596639 244.291765 L 563.596639 225.656471 L 540.151261 225.656471 z -" clip-path="url(#paff936fc9a)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#pf24e58d216)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -16220,12 +16220,12 @@ L 561.721548 236.673188 L 561.991345 236.673273 L 562.261142 236.673323 L 562.53094 236.673339 -" clip-path="url(#paff936fc9a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf24e58d216)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf24e58d216)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16243,7 +16243,7 @@ L 591.731092 244.291765 L 591.731092 225.656471 L 568.285714 225.656471 z -" clip-path="url(#p9af55b7d3e)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> +" clip-path="url(#p3e637633f2)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> @@ -16328,12 +16328,12 @@ L 589.856002 236.695308 L 590.125799 236.682988 L 590.395596 236.675722 L 590.665393 236.673339 -" clip-path="url(#p9af55b7d3e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3e637633f2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3e637633f2)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16351,7 +16351,7 @@ L 619.865546 244.291765 L 619.865546 225.656471 L 596.420168 225.656471 z -" clip-path="url(#p6d0a13549b)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p80e3670510)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -16436,12 +16436,12 @@ L 617.990456 236.680774 L 618.260253 236.676605 L 618.53005 236.674146 L 618.799847 236.673339 -" clip-path="url(#p6d0a13549b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p80e3670510)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p80e3670510)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16459,7 +16459,7 @@ L 113.445378 266.654118 L 113.445378 248.018824 L 90 248.018824 z -" clip-path="url(#pec4475b9b0)" style="fill: #6565ff; opacity: 0.5; stroke: #6565ff; stroke-linejoin: miter"/> +" clip-path="url(#pe597b17b86)" style="fill: #6565ff; opacity: 0.5; stroke: #6565ff; stroke-linejoin: miter"/> @@ -16544,12 +16544,12 @@ L 111.570287 257.534332 L 111.840085 257.52298 L 112.109882 257.516286 L 112.379679 257.51409 -" clip-path="url(#pec4475b9b0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe597b17b86)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe597b17b86)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16567,7 +16567,7 @@ L 141.579832 266.654118 L 141.579832 248.018824 L 118.134454 248.018824 z -" clip-path="url(#pef4a17bdf0)" style="fill: #ffb1b1; opacity: 0.5; stroke: #ffb1b1; stroke-linejoin: miter"/> +" clip-path="url(#p7320544b0c)" style="fill: #ffb1b1; opacity: 0.5; stroke: #ffb1b1; stroke-linejoin: miter"/> @@ -16652,12 +16652,12 @@ L 139.704741 257.502514 L 139.974538 257.509006 L 140.244336 257.512834 L 140.514133 257.51409 -" clip-path="url(#pef4a17bdf0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7320544b0c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7320544b0c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16675,7 +16675,7 @@ L 169.714286 266.654118 L 169.714286 248.018824 L 146.268908 248.018824 z -" clip-path="url(#paf9e17cf16)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> +" clip-path="url(#pd1afbfb9fd)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> @@ -16760,12 +16760,12 @@ L 167.839195 257.520305 L 168.108992 257.516819 L 168.378789 257.514764 L 168.648587 257.51409 -" clip-path="url(#paf9e17cf16)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd1afbfb9fd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd1afbfb9fd)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16783,7 +16783,7 @@ L 197.848739 266.654118 L 197.848739 248.018824 L 174.403361 248.018824 z -" clip-path="url(#p683a664ec4)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> +" clip-path="url(#pe62ec65888)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> @@ -16868,12 +16868,12 @@ L 195.973649 257.523118 L 196.243446 257.518055 L 196.513243 257.515069 L 196.78304 257.51409 -" clip-path="url(#p683a664ec4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe62ec65888)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe62ec65888)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16891,7 +16891,7 @@ L 225.983193 266.654118 L 225.983193 248.018824 L 202.537815 248.018824 z -" clip-path="url(#pe80ac3be76)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#p32ae73aa39)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -16976,12 +16976,12 @@ L 224.108103 257.504542 L 224.3779 257.509896 L 224.647697 257.513054 L 224.917494 257.51409 -" clip-path="url(#pe80ac3be76)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p32ae73aa39)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p32ae73aa39)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -16999,7 +16999,7 @@ L 254.117647 266.654118 L 254.117647 248.018824 L 230.672269 248.018824 z -" clip-path="url(#p7d8bf6b7cf)" style="fill: #ffb9b9; opacity: 0.5; stroke: #ffb9b9; stroke-linejoin: miter"/> +" clip-path="url(#pcdbda6f94c)" style="fill: #ffb9b9; opacity: 0.5; stroke: #ffb9b9; stroke-linejoin: miter"/> @@ -17084,12 +17084,12 @@ L 252.242556 257.490451 L 252.512354 257.503707 L 252.782151 257.511525 L 253.051948 257.51409 -" clip-path="url(#p7d8bf6b7cf)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcdbda6f94c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcdbda6f94c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17107,7 +17107,7 @@ L 282.252101 266.654118 L 282.252101 248.018824 L 258.806723 248.018824 z -" clip-path="url(#p7cf3a23499)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> +" clip-path="url(#p4f0bd5b590)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> @@ -17192,12 +17192,12 @@ L 280.37701 257.507306 L 280.646807 257.51111 L 280.916605 257.513354 L 281.186402 257.51409 -" clip-path="url(#p7cf3a23499)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4f0bd5b590)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4f0bd5b590)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17215,7 +17215,7 @@ L 310.386555 266.654118 L 310.386555 248.018824 L 286.941176 248.018824 z -" clip-path="url(#p344d3fb5b8)" style="fill: #ff6d6d; opacity: 0.5; stroke: #ff6d6d; stroke-linejoin: miter"/> +" clip-path="url(#pff0dfde012)" style="fill: #ff6d6d; opacity: 0.5; stroke: #ff6d6d; stroke-linejoin: miter"/> @@ -17300,12 +17300,12 @@ L 308.511464 257.492572 L 308.781261 257.504639 L 309.051058 257.511755 L 309.320856 257.51409 -" clip-path="url(#p344d3fb5b8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pff0dfde012)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pff0dfde012)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17323,7 +17323,7 @@ L 338.521008 266.654118 L 338.521008 248.018824 L 315.07563 248.018824 z -" clip-path="url(#p2c569de72b)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p07748b403b)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -17408,12 +17408,12 @@ L 336.645918 257.496544 L 336.915715 257.506384 L 337.185512 257.512186 L 337.455309 257.51409 -" clip-path="url(#p2c569de72b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p07748b403b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p07748b403b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17431,7 +17431,7 @@ L 366.655462 266.654118 L 366.655462 248.018824 L 343.210084 248.018824 z -" clip-path="url(#p4e7368d6a5)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> +" clip-path="url(#p3e27ca6991)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> @@ -17516,12 +17516,12 @@ L 364.780372 257.527932 L 365.050169 257.520169 L 365.319966 257.515591 L 365.589763 257.51409 -" clip-path="url(#p4e7368d6a5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3e27ca6991)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3e27ca6991)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17539,7 +17539,7 @@ L 394.789916 266.654118 L 394.789916 248.018824 L 371.344538 248.018824 z -" clip-path="url(#pc4a02d09e3)" style="fill: #ffbdbd; opacity: 0.5; stroke: #ffbdbd; stroke-linejoin: miter"/> +" clip-path="url(#pb75a92a633)" style="fill: #ffbdbd; opacity: 0.5; stroke: #ffbdbd; stroke-linejoin: miter"/> @@ -17624,12 +17624,12 @@ L 392.914825 257.506353 L 393.184623 257.510692 L 393.45442 257.51325 L 393.724217 257.51409 -" clip-path="url(#pc4a02d09e3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb75a92a633)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb75a92a633)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17647,7 +17647,7 @@ L 422.92437 266.654118 L 422.92437 248.018824 L 399.478992 248.018824 z -" clip-path="url(#pb5d40d3c80)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> +" clip-path="url(#p29da085961)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> @@ -17732,12 +17732,12 @@ L 421.049279 257.515663 L 421.319076 257.514781 L 421.588874 257.51426 L 421.858671 257.51409 -" clip-path="url(#pb5d40d3c80)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p29da085961)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p29da085961)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17755,7 +17755,7 @@ L 451.058824 266.654118 L 451.058824 248.018824 L 427.613445 248.018824 z -" clip-path="url(#p4aa3523ec1)" style="fill: #9595ff; opacity: 0.5; stroke: #9595ff; stroke-linejoin: miter"/> +" clip-path="url(#pdabdb559c4)" style="fill: #9595ff; opacity: 0.5; stroke: #9595ff; stroke-linejoin: miter"/> @@ -17840,12 +17840,12 @@ L 449.183733 257.518347 L 449.45353 257.515959 L 449.723327 257.514552 L 449.993125 257.51409 -" clip-path="url(#p4aa3523ec1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdabdb559c4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdabdb559c4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17863,7 +17863,7 @@ L 479.193277 266.654118 L 479.193277 248.018824 L 455.747899 248.018824 z -" clip-path="url(#p649052f78f)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> +" clip-path="url(#p0d209d61a7)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> @@ -17948,12 +17948,12 @@ L 477.318187 257.515027 L 477.587984 257.514501 L 477.857781 257.514191 L 478.127578 257.51409 -" clip-path="url(#p649052f78f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0d209d61a7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0d209d61a7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -17971,7 +17971,7 @@ L 507.327731 266.654118 L 507.327731 248.018824 L 483.882353 248.018824 z -" clip-path="url(#pb6d126db1c)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> +" clip-path="url(#p935c226086)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> @@ -18056,12 +18056,12 @@ L 505.45264 257.523423 L 505.722438 257.518189 L 505.992235 257.515102 L 506.262032 257.51409 -" clip-path="url(#pb6d126db1c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p935c226086)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p935c226086)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18079,7 +18079,7 @@ L 535.462185 266.654118 L 535.462185 248.018824 L 512.016807 248.018824 z -" clip-path="url(#p9aad5f6fac)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> +" clip-path="url(#p5d6f4f3a1f)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> @@ -18164,12 +18164,12 @@ L 533.587094 257.509686 L 533.856891 257.512155 L 534.126689 257.513612 L 534.396486 257.51409 -" clip-path="url(#p9aad5f6fac)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5d6f4f3a1f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5d6f4f3a1f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18187,7 +18187,7 @@ L 563.596639 266.654118 L 563.596639 248.018824 L 540.151261 248.018824 z -" clip-path="url(#p6c4e0ecda7)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p8004f6bb08)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -18272,12 +18272,12 @@ L 561.721548 257.514644 L 561.991345 257.514333 L 562.261142 257.51415 L 562.53094 257.51409 -" clip-path="url(#p6c4e0ecda7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8004f6bb08)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8004f6bb08)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18295,7 +18295,7 @@ L 591.731092 266.654118 L 591.731092 248.018824 L 568.285714 248.018824 z -" clip-path="url(#p2a57e6503b)" style="fill: #7d7dff; opacity: 0.5; stroke: #7d7dff; stroke-linejoin: miter"/> +" clip-path="url(#pc87ae59e68)" style="fill: #7d7dff; opacity: 0.5; stroke: #7d7dff; stroke-linejoin: miter"/> @@ -18380,12 +18380,12 @@ L 589.856002 257.537397 L 590.125799 257.524326 L 590.395596 257.516618 L 590.665393 257.51409 -" clip-path="url(#p2a57e6503b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc87ae59e68)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc87ae59e68)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18403,7 +18403,7 @@ L 619.865546 266.654118 L 619.865546 248.018824 L 596.420168 248.018824 z -" clip-path="url(#p68cc10715d)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> +" clip-path="url(#pbc839c33ae)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> @@ -18488,12 +18488,12 @@ L 617.990456 257.52 L 618.260253 257.516686 L 618.53005 257.514731 L 618.799847 257.51409 -" clip-path="url(#p68cc10715d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbc839c33ae)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbc839c33ae)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18511,7 +18511,7 @@ L 113.445378 289.016471 L 113.445378 270.381176 L 90 270.381176 z -" clip-path="url(#pe04c197eea)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> +" clip-path="url(#pad85b23999)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> @@ -18700,12 +18700,12 @@ L 111.570287 279.921851 L 111.840085 279.916215 L 112.109882 279.912891 L 112.379679 279.9118 -" clip-path="url(#pe04c197eea)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pad85b23999)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pad85b23999)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18723,7 +18723,7 @@ L 141.579832 289.016471 L 141.579832 270.381176 L 118.134454 270.381176 z -" clip-path="url(#p5ea1647dae)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> +" clip-path="url(#pe38e852e17)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> @@ -18808,12 +18808,12 @@ L 139.704741 279.905144 L 139.974538 279.908877 L 140.244336 279.911078 L 140.514133 279.9118 -" clip-path="url(#p5ea1647dae)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe38e852e17)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe38e852e17)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18831,7 +18831,7 @@ L 169.714286 289.016471 L 169.714286 270.381176 L 146.268908 270.381176 z -" clip-path="url(#paee30fa030)" style="fill: #3d3dff; opacity: 0.5; stroke: #3d3dff; stroke-linejoin: miter"/> +" clip-path="url(#pc7f8116636)" style="fill: #3d3dff; opacity: 0.5; stroke: #3d3dff; stroke-linejoin: miter"/> @@ -18916,12 +18916,12 @@ L 167.839195 279.922655 L 168.108992 279.916568 L 168.378789 279.912978 L 168.648587 279.9118 -" clip-path="url(#paee30fa030)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc7f8116636)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc7f8116636)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -18939,7 +18939,7 @@ L 197.848739 289.016471 L 197.848739 270.381176 L 174.403361 270.381176 z -" clip-path="url(#pcb6ad6337e)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> +" clip-path="url(#p48bfb29985)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> @@ -19024,12 +19024,12 @@ L 195.973649 279.916278 L 196.243446 279.913767 L 196.513243 279.912286 L 196.78304 279.9118 -" clip-path="url(#pcb6ad6337e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p48bfb29985)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p48bfb29985)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19047,7 +19047,7 @@ L 225.983193 289.016471 L 225.983193 270.381176 L 202.537815 270.381176 z -" clip-path="url(#p2a8ff50885)" style="fill: #7171ff; opacity: 0.5; stroke: #7171ff; stroke-linejoin: miter"/> +" clip-path="url(#p42588b2b3e)" style="fill: #7171ff; opacity: 0.5; stroke: #7171ff; stroke-linejoin: miter"/> @@ -19132,12 +19132,12 @@ L 224.108103 279.919405 L 224.3779 279.91514 L 224.647697 279.912625 L 224.917494 279.9118 -" clip-path="url(#p2a8ff50885)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p42588b2b3e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p42588b2b3e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19155,7 +19155,7 @@ L 254.117647 289.016471 L 254.117647 270.381176 L 230.672269 270.381176 z -" clip-path="url(#pdb575af27d)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> +" clip-path="url(#p731b0f5110)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> @@ -19240,12 +19240,12 @@ L 252.242556 279.90632 L 252.512354 279.909393 L 252.782151 279.911206 L 253.051948 279.9118 -" clip-path="url(#pdb575af27d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p731b0f5110)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p731b0f5110)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19263,7 +19263,7 @@ L 282.252101 289.016471 L 282.252101 270.381176 L 258.806723 270.381176 z -" clip-path="url(#p4e14353a8a)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p4c4e4a5202)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -19348,12 +19348,12 @@ L 280.37701 279.91682 L 280.646807 279.914005 L 280.916605 279.912345 L 281.186402 279.9118 -" clip-path="url(#p4e14353a8a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4c4e4a5202)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4c4e4a5202)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19371,7 +19371,7 @@ L 310.386555 289.016471 L 310.386555 270.381176 L 286.941176 270.381176 z -" clip-path="url(#pba212a21cb)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> +" clip-path="url(#pa08350853b)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> @@ -19456,12 +19456,12 @@ L 308.511464 279.903943 L 308.781261 279.908349 L 309.051058 279.910948 L 309.320856 279.9118 -" clip-path="url(#pba212a21cb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa08350853b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa08350853b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19479,7 +19479,7 @@ L 338.521008 289.016471 L 338.521008 270.381176 L 315.07563 270.381176 z -" clip-path="url(#p09704fe87b)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p8de49177d5)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -19564,12 +19564,12 @@ L 336.645918 279.899982 L 336.915715 279.90661 L 337.185512 279.910518 L 337.455309 279.9118 -" clip-path="url(#p09704fe87b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8de49177d5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8de49177d5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19587,7 +19587,7 @@ L 366.655462 289.016471 L 366.655462 270.381176 L 343.210084 270.381176 z -" clip-path="url(#p96d39ac743)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p6760d75683)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -19672,12 +19672,12 @@ L 364.780372 279.914681 L 365.050169 279.913066 L 365.319966 279.912113 L 365.589763 279.9118 -" clip-path="url(#p96d39ac743)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6760d75683)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6760d75683)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19695,7 +19695,7 @@ L 394.789916 289.016471 L 394.789916 270.381176 L 371.344538 270.381176 z -" clip-path="url(#p657bb364e8)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> +" clip-path="url(#pef00c7858d)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> @@ -19780,12 +19780,12 @@ L 392.914825 279.911205 L 393.184623 279.911539 L 393.45442 279.911736 L 393.724217 279.9118 -" clip-path="url(#p657bb364e8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pef00c7858d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pef00c7858d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19803,7 +19803,7 @@ L 422.92437 289.016471 L 422.92437 270.381176 L 399.478992 270.381176 z -" clip-path="url(#pe8037f7c46)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> +" clip-path="url(#p5d4b95cc37)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> @@ -19888,12 +19888,12 @@ L 421.049279 279.907792 L 421.319076 279.91004 L 421.588874 279.911366 L 421.858671 279.9118 -" clip-path="url(#pe8037f7c46)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5d4b95cc37)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5d4b95cc37)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -19911,7 +19911,7 @@ L 451.058824 289.016471 L 451.058824 270.381176 L 427.613445 270.381176 z -" clip-path="url(#pd1610bda9a)" style="fill: #8585ff; opacity: 0.5; stroke: #8585ff; stroke-linejoin: miter"/> +" clip-path="url(#p4e5d273452)" style="fill: #8585ff; opacity: 0.5; stroke: #8585ff; stroke-linejoin: miter"/> @@ -19996,12 +19996,12 @@ L 449.183733 279.918591 L 449.45353 279.914783 L 449.723327 279.912537 L 449.993125 279.9118 -" clip-path="url(#pd1610bda9a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4e5d273452)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4e5d273452)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20019,7 +20019,7 @@ L 479.193277 289.016471 L 479.193277 270.381176 L 455.747899 270.381176 z -" clip-path="url(#p3e5e01f6f7)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> +" clip-path="url(#pf2a0392bcd)" style="fill: #ffdddd; opacity: 0.5; stroke: #ffdddd; stroke-linejoin: miter"/> @@ -20104,12 +20104,12 @@ L 477.318187 279.904075 L 477.587984 279.908407 L 477.857781 279.910962 L 478.127578 279.9118 -" clip-path="url(#p3e5e01f6f7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf2a0392bcd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf2a0392bcd)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20127,7 +20127,7 @@ L 507.327731 289.016471 L 507.327731 270.381176 L 483.882353 270.381176 z -" clip-path="url(#p72426f9a9e)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> +" clip-path="url(#p83ecdb733f)" style="fill: #cdcdff; opacity: 0.5; stroke: #cdcdff; stroke-linejoin: miter"/> @@ -20212,12 +20212,12 @@ L 505.45264 279.914063 L 505.722438 279.912794 L 505.992235 279.912046 L 506.262032 279.9118 -" clip-path="url(#p72426f9a9e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p83ecdb733f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p83ecdb733f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20235,7 +20235,7 @@ L 535.462185 289.016471 L 535.462185 270.381176 L 512.016807 270.381176 z -" clip-path="url(#p21ebc72e2c)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> +" clip-path="url(#p3d16f37bce)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> @@ -20320,12 +20320,12 @@ L 533.587094 279.908496 L 533.856891 279.910349 L 534.126689 279.911442 L 534.396486 279.9118 -" clip-path="url(#p21ebc72e2c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3d16f37bce)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3d16f37bce)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20343,7 +20343,7 @@ L 563.596639 289.016471 L 563.596639 270.381176 L 540.151261 270.381176 z -" clip-path="url(#pc63c7174f5)" style="fill: #adadff; opacity: 0.5; stroke: #adadff; stroke-linejoin: miter"/> +" clip-path="url(#p9e194a3380)" style="fill: #adadff; opacity: 0.5; stroke: #adadff; stroke-linejoin: miter"/> @@ -20428,12 +20428,12 @@ L 561.721548 279.909286 L 561.991345 279.910696 L 562.261142 279.911528 L 562.53094 279.9118 -" clip-path="url(#pc63c7174f5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9e194a3380)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9e194a3380)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20451,7 +20451,7 @@ L 591.731092 289.016471 L 591.731092 270.381176 L 568.285714 270.381176 z -" clip-path="url(#p7b270a76ea)" style="fill: #0000d0; opacity: 0.5; stroke: #0000d0; stroke-linejoin: miter"/> +" clip-path="url(#p45d037e560)" style="fill: #0000d0; opacity: 0.5; stroke: #0000d0; stroke-linejoin: miter"/> @@ -20536,12 +20536,12 @@ L 589.856002 279.938338 L 590.125799 279.923456 L 590.395596 279.914679 L 590.665393 279.9118 -" clip-path="url(#p7b270a76ea)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p45d037e560)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p45d037e560)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20559,7 +20559,7 @@ L 619.865546 289.016471 L 619.865546 270.381176 L 596.420168 270.381176 z -" clip-path="url(#pc1b46ce49a)" style="fill: #6969ff; opacity: 0.5; stroke: #6969ff; stroke-linejoin: miter"/> +" clip-path="url(#p1c287faa0b)" style="fill: #6969ff; opacity: 0.5; stroke: #6969ff; stroke-linejoin: miter"/> @@ -20644,12 +20644,12 @@ L 617.990456 279.923673 L 618.260253 279.917015 L 618.53005 279.913088 L 618.799847 279.9118 -" clip-path="url(#pc1b46ce49a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1c287faa0b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1c287faa0b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20667,7 +20667,7 @@ L 113.445378 311.378824 L 113.445378 292.743529 L 90 292.743529 z -" clip-path="url(#pdf646a17f7)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p7dc4051be5)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -20752,12 +20752,12 @@ L 111.570287 301.001916 L 111.840085 300.997827 L 112.109882 300.995415 L 112.379679 300.994624 -" clip-path="url(#pdf646a17f7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7dc4051be5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7dc4051be5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20775,7 +20775,7 @@ L 141.579832 311.378824 L 141.579832 292.743529 L 118.134454 292.743529 z -" clip-path="url(#p26ddb42120)" style="fill: #fffdfd; opacity: 0.5; stroke: #fffdfd; stroke-linejoin: miter"/> +" clip-path="url(#p0afa2261fe)" style="fill: #fffdfd; opacity: 0.5; stroke: #fffdfd; stroke-linejoin: miter"/> @@ -20860,12 +20860,12 @@ L 139.704741 300.991346 L 139.974538 300.993185 L 140.244336 300.994269 L 140.514133 300.994624 -" clip-path="url(#p26ddb42120)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0afa2261fe)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0afa2261fe)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20883,7 +20883,7 @@ L 169.714286 311.378824 L 169.714286 292.743529 L 146.268908 292.743529 z -" clip-path="url(#pd9472a5a86)" style="fill: #0000b4; opacity: 0.5; stroke: #0000b4; stroke-linejoin: miter"/> +" clip-path="url(#p612238c2c7)" style="fill: #0000b4; opacity: 0.5; stroke: #0000b4; stroke-linejoin: miter"/> @@ -20968,12 +20968,12 @@ L 167.839195 301.010657 L 168.108992 301.001666 L 168.378789 300.996364 L 168.648587 300.994624 -" clip-path="url(#pd9472a5a86)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p612238c2c7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p612238c2c7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -20991,7 +20991,7 @@ L 197.848739 311.378824 L 197.848739 292.743529 L 174.403361 292.743529 z -" clip-path="url(#p9737bb1b89)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> +" clip-path="url(#p233e4d7360)" style="fill: #7575ff; opacity: 0.5; stroke: #7575ff; stroke-linejoin: miter"/> @@ -21076,12 +21076,12 @@ L 195.973649 301.005225 L 196.243446 300.99928 L 196.513243 300.995774 L 196.78304 300.994624 -" clip-path="url(#p9737bb1b89)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p233e4d7360)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p233e4d7360)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21099,7 +21099,7 @@ L 225.983193 311.378824 L 225.983193 292.743529 L 202.537815 292.743529 z -" clip-path="url(#p288cd7245f)" style="fill: #2d2dff; opacity: 0.5; stroke: #2d2dff; stroke-linejoin: miter"/> +" clip-path="url(#p410ba125e1)" style="fill: #2d2dff; opacity: 0.5; stroke: #2d2dff; stroke-linejoin: miter"/> @@ -21184,12 +21184,12 @@ L 224.108103 301.004492 L 224.3779 300.998958 L 224.647697 300.995695 L 224.917494 300.994624 -" clip-path="url(#p288cd7245f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p410ba125e1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p410ba125e1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21207,7 +21207,7 @@ L 254.117647 311.378824 L 254.117647 292.743529 L 230.672269 292.743529 z -" clip-path="url(#p793cfb0c94)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> +" clip-path="url(#p290a2c19d7)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> @@ -21292,12 +21292,12 @@ L 252.242556 300.991764 L 252.512354 300.993368 L 252.782151 300.994314 L 253.051948 300.994624 -" clip-path="url(#p793cfb0c94)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p290a2c19d7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p290a2c19d7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21315,7 +21315,7 @@ L 282.252101 311.378824 L 282.252101 292.743529 L 258.806723 292.743529 z -" clip-path="url(#pa5bb6f732d)" style="fill: #ddddff; opacity: 0.5; stroke: #ddddff; stroke-linejoin: miter"/> +" clip-path="url(#pfec3d8bdde)" style="fill: #ddddff; opacity: 0.5; stroke: #ddddff; stroke-linejoin: miter"/> @@ -21400,12 +21400,12 @@ L 280.37701 300.999115 L 280.646807 300.996597 L 280.916605 300.995112 L 281.186402 300.994624 -" clip-path="url(#pa5bb6f732d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfec3d8bdde)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfec3d8bdde)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21423,7 +21423,7 @@ L 310.386555 311.378824 L 310.386555 292.743529 L 286.941176 292.743529 z -" clip-path="url(#p88f0bb51b6)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> +" clip-path="url(#p7896abd58f)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> @@ -21508,12 +21508,12 @@ L 308.511464 300.996323 L 308.781261 300.99537 L 309.051058 300.994809 L 309.320856 300.994624 -" clip-path="url(#p88f0bb51b6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7896abd58f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7896abd58f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21531,7 +21531,7 @@ L 338.521008 311.378824 L 338.521008 292.743529 L 315.07563 292.743529 z -" clip-path="url(#p8093704fe2)" style="fill: #ffd1d1; opacity: 0.5; stroke: #ffd1d1; stroke-linejoin: miter"/> +" clip-path="url(#p44b9000450)" style="fill: #ffd1d1; opacity: 0.5; stroke: #ffd1d1; stroke-linejoin: miter"/> @@ -21616,12 +21616,12 @@ L 336.645918 300.990047 L 336.915715 300.992614 L 337.185512 300.994128 L 337.455309 300.994624 -" clip-path="url(#p8093704fe2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p44b9000450)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p44b9000450)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21639,7 +21639,7 @@ L 366.655462 311.378824 L 366.655462 292.743529 L 343.210084 292.743529 z -" clip-path="url(#pffe5597492)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p2a2a0821c3)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -21724,12 +21724,12 @@ L 364.780372 300.994484 L 365.050169 300.994563 L 365.319966 300.994609 L 365.589763 300.994624 -" clip-path="url(#pffe5597492)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2a2a0821c3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2a2a0821c3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21747,7 +21747,7 @@ L 394.789916 311.378824 L 394.789916 292.743529 L 371.344538 292.743529 z -" clip-path="url(#p2f4bd75036)" style="fill: #ff5959; opacity: 0.5; stroke: #ff5959; stroke-linejoin: miter"/> +" clip-path="url(#pe8d5777256)" style="fill: #ff5959; opacity: 0.5; stroke: #ff5959; stroke-linejoin: miter"/> @@ -21832,12 +21832,12 @@ L 392.914825 300.993743 L 393.184623 300.994237 L 393.45442 300.994529 L 393.724217 300.994624 -" clip-path="url(#p2f4bd75036)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe8d5777256)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe8d5777256)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21855,7 +21855,7 @@ L 422.92437 311.378824 L 422.92437 292.743529 L 399.478992 292.743529 z -" clip-path="url(#p41ab02049c)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#p32ffa56138)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -21940,12 +21940,12 @@ L 421.049279 300.99139 L 421.319076 300.993204 L 421.588874 300.994273 L 421.858671 300.994624 -" clip-path="url(#p41ab02049c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p32ffa56138)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p32ffa56138)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -21963,7 +21963,7 @@ L 451.058824 311.378824 L 451.058824 292.743529 L 427.613445 292.743529 z -" clip-path="url(#pbdebf22f05)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> +" clip-path="url(#peaf61c15e7)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> @@ -22048,12 +22048,12 @@ L 449.183733 300.990506 L 449.45353 300.992816 L 449.723327 300.994178 L 449.993125 300.994624 -" clip-path="url(#pbdebf22f05)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#peaf61c15e7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#peaf61c15e7)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22071,7 +22071,7 @@ L 479.193277 311.378824 L 479.193277 292.743529 L 455.747899 292.743529 z -" clip-path="url(#p515fc82d5c)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> +" clip-path="url(#p7761d80c40)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> @@ -22156,12 +22156,12 @@ L 477.318187 300.990817 L 477.587984 300.992952 L 477.857781 300.994211 L 478.127578 300.994624 -" clip-path="url(#p515fc82d5c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7761d80c40)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7761d80c40)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22179,7 +22179,7 @@ L 507.327731 311.378824 L 507.327731 292.743529 L 483.882353 292.743529 z -" clip-path="url(#p7525a41f45)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> +" clip-path="url(#p3586d197f3)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> @@ -22264,12 +22264,12 @@ L 505.45264 300.995656 L 505.722438 300.995078 L 505.992235 300.994736 L 506.262032 300.994624 -" clip-path="url(#p7525a41f45)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3586d197f3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3586d197f3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22287,7 +22287,7 @@ L 535.462185 311.378824 L 535.462185 292.743529 L 512.016807 292.743529 z -" clip-path="url(#p7876017902)" style="fill: #ffc5c5; opacity: 0.5; stroke: #ffc5c5; stroke-linejoin: miter"/> +" clip-path="url(#pa4a73e9d88)" style="fill: #ffc5c5; opacity: 0.5; stroke: #ffc5c5; stroke-linejoin: miter"/> @@ -22372,12 +22372,12 @@ L 533.587094 300.993413 L 533.856891 300.994092 L 534.126689 300.994493 L 534.396486 300.994624 -" clip-path="url(#p7876017902)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa4a73e9d88)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa4a73e9d88)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22395,7 +22395,7 @@ L 563.596639 311.378824 L 563.596639 292.743529 L 540.151261 292.743529 z -" clip-path="url(#pcebaaea103)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> +" clip-path="url(#p6bb0e13c65)" style="fill: #ffd9d9; opacity: 0.5; stroke: #ffd9d9; stroke-linejoin: miter"/> @@ -22480,12 +22480,12 @@ L 561.721548 300.995005 L 561.991345 300.994792 L 562.261142 300.994666 L 562.53094 300.994624 -" clip-path="url(#pcebaaea103)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6bb0e13c65)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6bb0e13c65)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22503,7 +22503,7 @@ L 591.731092 311.378824 L 591.731092 292.743529 L 568.285714 292.743529 z -" clip-path="url(#p667bd811c7)" style="fill: #00004c; opacity: 0.5; stroke: #00004c; stroke-linejoin: miter"/> +" clip-path="url(#pd01c6b415a)" style="fill: #00004c; opacity: 0.5; stroke: #00004c; stroke-linejoin: miter"/> @@ -22588,12 +22588,12 @@ L 589.856002 301.024648 L 590.125799 301.007811 L 590.395596 300.997881 L 590.665393 300.994624 -" clip-path="url(#p667bd811c7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd01c6b415a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd01c6b415a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22611,7 +22611,7 @@ L 619.865546 311.378824 L 619.865546 292.743529 L 596.420168 292.743529 z -" clip-path="url(#peec5f9eef7)" style="fill: #2525ff; opacity: 0.5; stroke: #2525ff; stroke-linejoin: miter"/> +" clip-path="url(#pe6c2f7b6bf)" style="fill: #2525ff; opacity: 0.5; stroke: #2525ff; stroke-linejoin: miter"/> @@ -22696,12 +22696,12 @@ L 617.990456 301.007524 L 618.260253 301.00029 L 618.53005 300.996024 L 618.799847 300.994624 -" clip-path="url(#peec5f9eef7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe6c2f7b6bf)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe6c2f7b6bf)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22719,7 +22719,7 @@ L 113.445378 333.741176 L 113.445378 315.105882 L 90 315.105882 z -" clip-path="url(#p2e6782d8bd)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#pe6a31e3b84)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -22804,12 +22804,12 @@ L 111.570287 322.525789 L 111.840085 322.528704 L 112.109882 322.530424 L 112.379679 322.530988 -" clip-path="url(#p2e6782d8bd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe6a31e3b84)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe6a31e3b84)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22827,7 +22827,7 @@ L 141.579832 333.741176 L 141.579832 315.105882 L 118.134454 315.105882 z -" clip-path="url(#pcf5c17fc87)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> +" clip-path="url(#p993df30986)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> @@ -22912,12 +22912,12 @@ L 139.704741 322.531749 L 139.974538 322.531322 L 140.244336 322.531071 L 140.514133 322.530988 -" clip-path="url(#pcf5c17fc87)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p993df30986)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p993df30986)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -22935,7 +22935,7 @@ L 169.714286 333.741176 L 169.714286 315.105882 L 146.268908 315.105882 z -" clip-path="url(#p2b5a8e9a23)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> +" clip-path="url(#p8e73d30016)" style="fill: #ffcdcd; opacity: 0.5; stroke: #ffcdcd; stroke-linejoin: miter"/> @@ -23020,12 +23020,12 @@ L 167.839195 322.529704 L 168.108992 322.530424 L 168.378789 322.530849 L 168.648587 322.530988 -" clip-path="url(#p2b5a8e9a23)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8e73d30016)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8e73d30016)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23043,7 +23043,7 @@ L 197.848739 333.741176 L 197.848739 315.105882 L 174.403361 315.105882 z -" clip-path="url(#p0392a32810)" style="fill: #ff5959; opacity: 0.5; stroke: #ff5959; stroke-linejoin: miter"/> +" clip-path="url(#p74b995ad20)" style="fill: #ff5959; opacity: 0.5; stroke: #ff5959; stroke-linejoin: miter"/> @@ -23128,12 +23128,12 @@ L 195.973649 322.526742 L 196.243446 322.529123 L 196.513243 322.530527 L 196.78304 322.530988 -" clip-path="url(#p0392a32810)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p74b995ad20)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p74b995ad20)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23151,7 +23151,7 @@ L 225.983193 333.741176 L 225.983193 315.105882 L 202.537815 315.105882 z -" clip-path="url(#pe1664c6bc3)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> +" clip-path="url(#pe9bdff4a76)" style="fill: #ffe9e9; opacity: 0.5; stroke: #ffe9e9; stroke-linejoin: miter"/> @@ -23236,12 +23236,12 @@ L 224.108103 322.535822 L 224.3779 322.533111 L 224.647697 322.531512 L 224.917494 322.530988 -" clip-path="url(#pe1664c6bc3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe9bdff4a76)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe9bdff4a76)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23259,7 +23259,7 @@ L 254.117647 333.741176 L 254.117647 315.105882 L 230.672269 315.105882 z -" clip-path="url(#p835600de6b)" style="fill: #2d2dff; opacity: 0.5; stroke: #2d2dff; stroke-linejoin: miter"/> +" clip-path="url(#p1ba3d5dec6)" style="fill: #2d2dff; opacity: 0.5; stroke: #2d2dff; stroke-linejoin: miter"/> @@ -23344,12 +23344,12 @@ L 252.242556 322.541348 L 252.512354 322.535538 L 252.782151 322.532112 L 253.051948 322.530988 -" clip-path="url(#p835600de6b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1ba3d5dec6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1ba3d5dec6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23367,7 +23367,7 @@ L 282.252101 333.741176 L 282.252101 315.105882 L 258.806723 315.105882 z -" clip-path="url(#paad500e6ad)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> +" clip-path="url(#p23cb7932ca)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> @@ -23452,12 +23452,12 @@ L 280.37701 322.538457 L 280.646807 322.534268 L 280.916605 322.531798 L 281.186402 322.530988 -" clip-path="url(#paad500e6ad)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p23cb7932ca)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p23cb7932ca)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23475,7 +23475,7 @@ L 310.386555 333.741176 L 310.386555 315.105882 L 286.941176 315.105882 z -" clip-path="url(#p09e21916dc)" style="fill: #0000fa; opacity: 0.5; stroke: #0000fa; stroke-linejoin: miter"/> +" clip-path="url(#p656a385e07)" style="fill: #0000fa; opacity: 0.5; stroke: #0000fa; stroke-linejoin: miter"/> @@ -23560,12 +23560,12 @@ L 308.511464 322.54799 L 308.781261 322.538455 L 309.051058 322.532832 L 309.320856 322.530988 -" clip-path="url(#p09e21916dc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p656a385e07)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p656a385e07)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23583,7 +23583,7 @@ L 338.521008 333.741176 L 338.521008 315.105882 L 315.07563 315.105882 z -" clip-path="url(#p9d3d848f48)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> +" clip-path="url(#p2f20c5a282)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> @@ -23668,12 +23668,12 @@ L 336.645918 322.539368 L 336.915715 322.534668 L 337.185512 322.531897 L 337.455309 322.530988 -" clip-path="url(#p9d3d848f48)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2f20c5a282)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2f20c5a282)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23691,7 +23691,7 @@ L 366.655462 333.741176 L 366.655462 315.105882 L 343.210084 315.105882 z -" clip-path="url(#p4f0ee939c7)" style="fill: #ffb9b9; opacity: 0.5; stroke: #ffb9b9; stroke-linejoin: miter"/> +" clip-path="url(#p768bffe827)" style="fill: #ffb9b9; opacity: 0.5; stroke: #ffb9b9; stroke-linejoin: miter"/> @@ -23776,12 +23776,12 @@ L 364.780372 322.529654 L 365.050169 322.530402 L 365.319966 322.530843 L 365.589763 322.530988 -" clip-path="url(#p4f0ee939c7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p768bffe827)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p768bffe827)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23799,7 +23799,7 @@ L 394.789916 333.741176 L 394.789916 315.105882 L 371.344538 315.105882 z -" clip-path="url(#p0efb77703c)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> +" clip-path="url(#p7c12cd599f)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> @@ -23884,12 +23884,12 @@ L 392.914825 322.529935 L 393.184623 322.530526 L 393.45442 322.530874 L 393.724217 322.530988 -" clip-path="url(#p0efb77703c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7c12cd599f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7c12cd599f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -23907,7 +23907,7 @@ L 422.92437 333.741176 L 422.92437 315.105882 L 399.478992 315.105882 z -" clip-path="url(#p11b34b8692)" style="fill: #ff9595; opacity: 0.5; stroke: #ff9595; stroke-linejoin: miter"/> +" clip-path="url(#p0556a59d7b)" style="fill: #ff9595; opacity: 0.5; stroke: #ff9595; stroke-linejoin: miter"/> @@ -23992,12 +23992,12 @@ L 421.049279 322.527167 L 421.319076 322.52931 L 421.588874 322.530574 L 421.858671 322.530988 -" clip-path="url(#p11b34b8692)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0556a59d7b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0556a59d7b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24015,7 +24015,7 @@ L 451.058824 333.741176 L 451.058824 315.105882 L 427.613445 315.105882 z -" clip-path="url(#pe001d75801)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#pbba49080a8)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -24100,12 +24100,12 @@ L 449.183733 322.532624 L 449.45353 322.531707 L 449.723327 322.531166 L 449.993125 322.530988 -" clip-path="url(#pe001d75801)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbba49080a8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pbba49080a8)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24123,7 +24123,7 @@ L 479.193277 333.741176 L 479.193277 315.105882 L 455.747899 315.105882 z -" clip-path="url(#p23071db74c)" style="fill: #ff6969; opacity: 0.5; stroke: #ff6969; stroke-linejoin: miter"/> +" clip-path="url(#p7d411765ad)" style="fill: #ff6969; opacity: 0.5; stroke: #ff6969; stroke-linejoin: miter"/> @@ -24208,12 +24208,12 @@ L 477.318187 322.52435 L 477.587984 322.528073 L 477.857781 322.530268 L 478.127578 322.530988 -" clip-path="url(#p23071db74c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7d411765ad)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7d411765ad)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24231,7 +24231,7 @@ L 507.327731 333.741176 L 507.327731 315.105882 L 483.882353 315.105882 z -" clip-path="url(#p2f3e8b1248)" style="fill: #ff9595; opacity: 0.5; stroke: #ff9595; stroke-linejoin: miter"/> +" clip-path="url(#p4e303b3838)" style="fill: #ff9595; opacity: 0.5; stroke: #ff9595; stroke-linejoin: miter"/> @@ -24316,12 +24316,12 @@ L 505.45264 322.525609 L 505.722438 322.528626 L 505.992235 322.530405 L 506.262032 322.530988 -" clip-path="url(#p2f3e8b1248)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4e303b3838)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4e303b3838)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24339,7 +24339,7 @@ L 535.462185 333.741176 L 535.462185 315.105882 L 512.016807 315.105882 z -" clip-path="url(#p07896f5fa0)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> +" clip-path="url(#p242c765a71)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> @@ -24424,12 +24424,12 @@ L 533.587094 322.528155 L 533.856891 322.529744 L 534.126689 322.530681 L 534.396486 322.530988 -" clip-path="url(#p07896f5fa0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p242c765a71)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p242c765a71)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24447,7 +24447,7 @@ L 563.596639 333.741176 L 563.596639 315.105882 L 540.151261 315.105882 z -" clip-path="url(#pc29995acad)" style="fill: #c9c9ff; opacity: 0.5; stroke: #c9c9ff; stroke-linejoin: miter"/> +" clip-path="url(#p4338c19c9f)" style="fill: #c9c9ff; opacity: 0.5; stroke: #c9c9ff; stroke-linejoin: miter"/> @@ -24532,12 +24532,12 @@ L 561.721548 322.531563 L 561.991345 322.531241 L 562.261142 322.53105 L 562.53094 322.530988 -" clip-path="url(#pc29995acad)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4338c19c9f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4338c19c9f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24555,7 +24555,7 @@ L 591.731092 333.741176 L 591.731092 315.105882 L 568.285714 315.105882 z -" clip-path="url(#p6478a9d58a)" style="fill: #000055; opacity: 0.5; stroke: #000055; stroke-linejoin: miter"/> +" clip-path="url(#p6debf64f02)" style="fill: #000055; opacity: 0.5; stroke: #000055; stroke-linejoin: miter"/> @@ -24640,12 +24640,12 @@ L 589.856002 322.561348 L 590.125799 322.544322 L 590.395596 322.534282 L 590.665393 322.530988 -" clip-path="url(#p6478a9d58a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6debf64f02)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6debf64f02)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24663,7 +24663,7 @@ L 619.865546 333.741176 L 619.865546 315.105882 L 596.420168 315.105882 z -" clip-path="url(#p3b80dec32f)" style="fill: #1919ff; opacity: 0.5; stroke: #1919ff; stroke-linejoin: miter"/> +" clip-path="url(#pf2967f3801)" style="fill: #1919ff; opacity: 0.5; stroke: #1919ff; stroke-linejoin: miter"/> @@ -24748,12 +24748,12 @@ L 617.990456 322.545023 L 618.260253 322.537152 L 618.53005 322.532511 L 618.799847 322.530988 -" clip-path="url(#p3b80dec32f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf2967f3801)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf2967f3801)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24771,7 +24771,7 @@ L 113.445378 356.103529 L 113.445378 337.468235 L 90 337.468235 z -" clip-path="url(#p82c01defcf)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> +" clip-path="url(#p5aee14effc)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> @@ -24856,12 +24856,12 @@ L 111.570287 347.58233 L 111.840085 347.577814 L 112.109882 347.575151 L 112.379679 347.574277 -" clip-path="url(#p82c01defcf)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5aee14effc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5aee14effc)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24879,7 +24879,7 @@ L 141.579832 356.103529 L 141.579832 337.468235 L 118.134454 337.468235 z -" clip-path="url(#pb53ab6bf85)" style="fill: #6969ff; opacity: 0.5; stroke: #6969ff; stroke-linejoin: miter"/> +" clip-path="url(#p845fbf2446)" style="fill: #6969ff; opacity: 0.5; stroke: #6969ff; stroke-linejoin: miter"/> @@ -24964,12 +24964,12 @@ L 139.704741 347.586485 L 139.974538 347.579639 L 140.244336 347.575602 L 140.514133 347.574277 -" clip-path="url(#pb53ab6bf85)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p845fbf2446)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p845fbf2446)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -24987,7 +24987,7 @@ L 169.714286 356.103529 L 169.714286 337.468235 L 146.268908 337.468235 z -" clip-path="url(#pffdbd8662c)" style="fill: #5151ff; opacity: 0.5; stroke: #5151ff; stroke-linejoin: miter"/> +" clip-path="url(#p5d150bd2bc)" style="fill: #5151ff; opacity: 0.5; stroke: #5151ff; stroke-linejoin: miter"/> @@ -25072,12 +25072,12 @@ L 167.839195 347.593386 L 168.108992 347.58267 L 168.378789 347.57635 L 168.648587 347.574277 -" clip-path="url(#pffdbd8662c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5d150bd2bc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5d150bd2bc)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25095,7 +25095,7 @@ L 197.848739 356.103529 L 197.848739 337.468235 L 174.403361 337.468235 z -" clip-path="url(#p8f3733f5e7)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#p83f0dbefeb)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -25180,12 +25180,12 @@ L 195.973649 347.577055 L 196.243446 347.575497 L 196.513243 347.574579 L 196.78304 347.574277 -" clip-path="url(#p8f3733f5e7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p83f0dbefeb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p83f0dbefeb)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25203,7 +25203,7 @@ L 225.983193 356.103529 L 225.983193 337.468235 L 202.537815 337.468235 z -" clip-path="url(#p84a7492904)" style="fill: #0000de; opacity: 0.5; stroke: #0000de; stroke-linejoin: miter"/> +" clip-path="url(#pf4e59a63d1)" style="fill: #0000de; opacity: 0.5; stroke: #0000de; stroke-linejoin: miter"/> @@ -25288,12 +25288,12 @@ L 224.108103 347.595181 L 224.3779 347.583458 L 224.647697 347.576545 L 224.917494 347.574277 -" clip-path="url(#p84a7492904)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf4e59a63d1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf4e59a63d1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25311,7 +25311,7 @@ L 254.117647 356.103529 L 254.117647 337.468235 L 230.672269 337.468235 z -" clip-path="url(#p526622246b)" style="fill: #0505ff; opacity: 0.5; stroke: #0505ff; stroke-linejoin: miter"/> +" clip-path="url(#p0ac6ac36ee)" style="fill: #0505ff; opacity: 0.5; stroke: #0505ff; stroke-linejoin: miter"/> @@ -25396,12 +25396,12 @@ L 252.242556 347.594712 L 252.512354 347.583252 L 252.782151 347.576494 L 253.051948 347.574277 -" clip-path="url(#p526622246b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0ac6ac36ee)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0ac6ac36ee)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25419,7 +25419,7 @@ L 282.252101 356.103529 L 282.252101 337.468235 L 258.806723 337.468235 z -" clip-path="url(#p5dca5231d7)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> +" clip-path="url(#pc1364e2f8e)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> @@ -25504,12 +25504,12 @@ L 280.37701 347.581915 L 280.646807 347.577632 L 280.916605 347.575106 L 281.186402 347.574277 -" clip-path="url(#p5dca5231d7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc1364e2f8e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc1364e2f8e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25527,7 +25527,7 @@ L 310.386555 356.103529 L 310.386555 337.468235 L 286.941176 337.468235 z -" clip-path="url(#p4c9f592c1e)" style="fill: #4d4dff; opacity: 0.5; stroke: #4d4dff; stroke-linejoin: miter"/> +" clip-path="url(#p8baed3cc0f)" style="fill: #4d4dff; opacity: 0.5; stroke: #4d4dff; stroke-linejoin: miter"/> @@ -25612,12 +25612,12 @@ L 308.511464 347.591438 L 308.781261 347.581815 L 309.051058 347.576139 L 309.320856 347.574277 -" clip-path="url(#p4c9f592c1e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8baed3cc0f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8baed3cc0f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25635,7 +25635,7 @@ L 338.521008 356.103529 L 338.521008 337.468235 L 315.07563 337.468235 z -" clip-path="url(#p7ef0dc4652)" style="fill: #1d1dff; opacity: 0.5; stroke: #1d1dff; stroke-linejoin: miter"/> +" clip-path="url(#pcc1323642e)" style="fill: #1d1dff; opacity: 0.5; stroke: #1d1dff; stroke-linejoin: miter"/> @@ -25720,12 +25720,12 @@ L 336.645918 347.588832 L 336.915715 347.58067 L 337.185512 347.575856 L 337.455309 347.574277 -" clip-path="url(#p7ef0dc4652)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcc1323642e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcc1323642e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25743,7 +25743,7 @@ L 366.655462 356.103529 L 366.655462 337.468235 L 343.210084 337.468235 z -" clip-path="url(#pa87599f5d5)" style="fill: #4545ff; opacity: 0.5; stroke: #4545ff; stroke-linejoin: miter"/> +" clip-path="url(#p6708ea8f98)" style="fill: #4545ff; opacity: 0.5; stroke: #4545ff; stroke-linejoin: miter"/> @@ -25828,12 +25828,12 @@ L 364.780372 347.583411 L 365.050169 347.578289 L 365.319966 347.575268 L 365.589763 347.574277 -" clip-path="url(#pa87599f5d5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6708ea8f98)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6708ea8f98)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25851,7 +25851,7 @@ L 394.789916 356.103529 L 394.789916 337.468235 L 371.344538 337.468235 z -" clip-path="url(#pc6f529eb9e)" style="fill: #ffd5d5; opacity: 0.5; stroke: #ffd5d5; stroke-linejoin: miter"/> +" clip-path="url(#p45c102d7ec)" style="fill: #ffd5d5; opacity: 0.5; stroke: #ffd5d5; stroke-linejoin: miter"/> @@ -25936,12 +25936,12 @@ L 392.914825 347.572295 L 393.184623 347.573407 L 393.45442 347.574062 L 393.724217 347.574277 -" clip-path="url(#pc6f529eb9e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p45c102d7ec)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p45c102d7ec)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -25959,7 +25959,7 @@ L 422.92437 356.103529 L 422.92437 337.468235 L 399.478992 337.468235 z -" clip-path="url(#pa41621b1e2)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#p05ac4edaa6)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -26044,12 +26044,12 @@ L 421.049279 347.575632 L 421.319076 347.574872 L 421.588874 347.574424 L 421.858671 347.574277 -" clip-path="url(#pa41621b1e2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p05ac4edaa6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p05ac4edaa6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26067,7 +26067,7 @@ L 451.058824 356.103529 L 451.058824 337.468235 L 427.613445 337.468235 z -" clip-path="url(#pf9c0cc3d3b)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p7ab502c125)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -26152,12 +26152,12 @@ L 449.183733 347.570467 L 449.45353 347.572604 L 449.723327 347.573864 L 449.993125 347.574277 -" clip-path="url(#pf9c0cc3d3b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ab502c125)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7ab502c125)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26175,7 +26175,7 @@ L 479.193277 356.103529 L 479.193277 337.468235 L 455.747899 337.468235 z -" clip-path="url(#p28d38c7d08)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> +" clip-path="url(#p8fcde2ed4d)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> @@ -26260,12 +26260,12 @@ L 477.318187 347.574144 L 477.587984 347.574219 L 477.857781 347.574263 L 478.127578 347.574277 -" clip-path="url(#p28d38c7d08)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8fcde2ed4d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8fcde2ed4d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26283,7 +26283,7 @@ L 507.327731 356.103529 L 507.327731 337.468235 L 483.882353 337.468235 z -" clip-path="url(#p1c21bf564d)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> +" clip-path="url(#p680a0bfeb4)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> @@ -26368,12 +26368,12 @@ L 505.45264 347.572207 L 505.722438 347.573368 L 505.992235 347.574053 L 506.262032 347.574277 -" clip-path="url(#p1c21bf564d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p680a0bfeb4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p680a0bfeb4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26391,7 +26391,7 @@ L 535.462185 356.103529 L 535.462185 337.468235 L 512.016807 337.468235 z -" clip-path="url(#p318b50fedd)" style="fill: #ffeded; opacity: 0.5; stroke: #ffeded; stroke-linejoin: miter"/> +" clip-path="url(#p3b7351b77a)" style="fill: #ffeded; opacity: 0.5; stroke: #ffeded; stroke-linejoin: miter"/> @@ -26476,12 +26476,12 @@ L 533.587094 347.578742 L 533.856891 347.576238 L 534.126689 347.574762 L 534.396486 347.574277 -" clip-path="url(#p318b50fedd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3b7351b77a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3b7351b77a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26499,7 +26499,7 @@ L 563.596639 356.103529 L 563.596639 337.468235 L 540.151261 337.468235 z -" clip-path="url(#pfd8182c6a2)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> +" clip-path="url(#pb21a42c1e0)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> @@ -26584,12 +26584,12 @@ L 561.721548 347.575337 L 561.991345 347.574743 L 562.261142 347.574392 L 562.53094 347.574277 -" clip-path="url(#pfd8182c6a2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb21a42c1e0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb21a42c1e0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26607,7 +26607,7 @@ L 591.731092 356.103529 L 591.731092 337.468235 L 568.285714 337.468235 z -" clip-path="url(#p2d3a5a7ec4)" style="fill: #ff8181; opacity: 0.5; stroke: #ff8181; stroke-linejoin: miter"/> +" clip-path="url(#pdec9670b00)" style="fill: #ff8181; opacity: 0.5; stroke: #ff8181; stroke-linejoin: miter"/> @@ -26692,12 +26692,12 @@ L 589.856002 347.567215 L 590.125799 347.571176 L 590.395596 347.573511 L 590.665393 347.574277 -" clip-path="url(#p2d3a5a7ec4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdec9670b00)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdec9670b00)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26715,7 +26715,7 @@ L 619.865546 356.103529 L 619.865546 337.468235 L 596.420168 337.468235 z -" clip-path="url(#pd8a8a03cc1)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> +" clip-path="url(#p178cc84613)" style="fill: #ff8d8d; opacity: 0.5; stroke: #ff8d8d; stroke-linejoin: miter"/> @@ -26800,12 +26800,12 @@ L 617.990456 347.570843 L 618.260253 347.572769 L 618.53005 347.573905 L 618.799847 347.574277 -" clip-path="url(#pd8a8a03cc1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p178cc84613)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p178cc84613)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26823,7 +26823,7 @@ L 113.445378 378.465882 L 113.445378 359.830588 L 90 359.830588 z -" clip-path="url(#p9e4a180832)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> +" clip-path="url(#p171182d85a)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> @@ -26908,12 +26908,12 @@ L 111.570287 369.250612 L 111.840085 369.251272 L 112.109882 369.251661 L 112.379679 369.251788 -" clip-path="url(#p9e4a180832)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p171182d85a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p171182d85a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -26931,7 +26931,7 @@ L 141.579832 378.465882 L 141.579832 359.830588 L 118.134454 359.830588 z -" clip-path="url(#p003c3fa978)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#p10c66555b8)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -27016,12 +27016,12 @@ L 139.704741 369.249925 L 139.974538 369.25097 L 140.244336 369.251586 L 140.514133 369.251788 -" clip-path="url(#p003c3fa978)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10c66555b8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10c66555b8)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27039,7 +27039,7 @@ L 169.714286 378.465882 L 169.714286 359.830588 L 146.268908 359.830588 z -" clip-path="url(#p90738b0cc9)" style="fill: #ff5959; opacity: 0.5; stroke: #ff5959; stroke-linejoin: miter"/> +" clip-path="url(#pb6d9cec5d1)" style="fill: #ff5959; opacity: 0.5; stroke: #ff5959; stroke-linejoin: miter"/> @@ -27124,12 +27124,12 @@ L 167.839195 369.252233 L 168.108992 369.251984 L 168.378789 369.251837 L 168.648587 369.251788 -" clip-path="url(#p90738b0cc9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb6d9cec5d1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb6d9cec5d1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27147,7 +27147,7 @@ L 197.848739 378.465882 L 197.848739 359.830588 L 174.403361 359.830588 z -" clip-path="url(#p36431d8e76)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> +" clip-path="url(#pe869daef09)" style="fill: #ffe5e5; opacity: 0.5; stroke: #ffe5e5; stroke-linejoin: miter"/> @@ -27232,12 +27232,12 @@ L 195.973649 369.249071 L 196.243446 369.250595 L 196.513243 369.251494 L 196.78304 369.251788 -" clip-path="url(#p36431d8e76)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe869daef09)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe869daef09)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27255,7 +27255,7 @@ L 225.983193 378.465882 L 225.983193 359.830588 L 202.537815 359.830588 z -" clip-path="url(#p6297a8e0a5)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#p6c25bace04)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -27340,12 +27340,12 @@ L 224.108103 369.254011 L 224.3779 369.252764 L 224.647697 369.252029 L 224.917494 369.251788 -" clip-path="url(#p6297a8e0a5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6c25bace04)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6c25bace04)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27363,7 +27363,7 @@ L 254.117647 378.465882 L 254.117647 359.830588 L 230.672269 359.830588 z -" clip-path="url(#p00d8e078d3)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> +" clip-path="url(#p88d180479e)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> @@ -27448,12 +27448,12 @@ L 252.242556 369.256674 L 252.512354 369.253934 L 252.782151 369.252318 L 253.051948 369.251788 -" clip-path="url(#p00d8e078d3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p88d180479e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p88d180479e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27471,7 +27471,7 @@ L 282.252101 378.465882 L 282.252101 359.830588 L 258.806723 359.830588 z -" clip-path="url(#p5ab17500cf)" style="fill: #7d7dff; opacity: 0.5; stroke: #7d7dff; stroke-linejoin: miter"/> +" clip-path="url(#p6517b8f9fe)" style="fill: #7d7dff; opacity: 0.5; stroke: #7d7dff; stroke-linejoin: miter"/> @@ -27556,12 +27556,12 @@ L 280.37701 369.258876 L 280.646807 369.254901 L 280.916605 369.252557 L 281.186402 369.251788 -" clip-path="url(#p5ab17500cf)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6517b8f9fe)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6517b8f9fe)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27579,7 +27579,7 @@ L 310.386555 378.465882 L 310.386555 359.830588 L 286.941176 359.830588 z -" clip-path="url(#p5a3b170067)" style="fill: #0000ae; opacity: 0.5; stroke: #0000ae; stroke-linejoin: miter"/> +" clip-path="url(#pd2778a267c)" style="fill: #0000ae; opacity: 0.5; stroke: #0000ae; stroke-linejoin: miter"/> @@ -27664,12 +27664,12 @@ L 308.511464 369.27243 L 308.781261 369.260854 L 309.051058 369.254028 L 309.320856 369.251788 -" clip-path="url(#p5a3b170067)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd2778a267c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd2778a267c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27687,7 +27687,7 @@ L 338.521008 378.465882 L 338.521008 359.830588 L 315.07563 359.830588 z -" clip-path="url(#p1b8dc0cb84)" style="fill: #4141ff; opacity: 0.5; stroke: #4141ff; stroke-linejoin: miter"/> +" clip-path="url(#p59bb58e002)" style="fill: #4141ff; opacity: 0.5; stroke: #4141ff; stroke-linejoin: miter"/> @@ -27772,12 +27772,12 @@ L 336.645918 369.26069 L 336.915715 369.255698 L 337.185512 369.252754 L 337.455309 369.251788 -" clip-path="url(#p1b8dc0cb84)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p59bb58e002)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p59bb58e002)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27795,7 +27795,7 @@ L 366.655462 378.465882 L 366.655462 359.830588 L 343.210084 359.830588 z -" clip-path="url(#pd6d748ac1b)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> +" clip-path="url(#pda3f80f4e0)" style="fill: #ffa9a9; opacity: 0.5; stroke: #ffa9a9; stroke-linejoin: miter"/> @@ -27880,12 +27880,12 @@ L 364.780372 369.241203 L 365.050169 369.247139 L 365.319966 369.25064 L 365.589763 369.251788 -" clip-path="url(#pd6d748ac1b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pda3f80f4e0)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pda3f80f4e0)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -27903,7 +27903,7 @@ L 394.789916 378.465882 L 394.789916 359.830588 L 371.344538 359.830588 z -" clip-path="url(#p03ca37afdf)" style="fill: #ff7575; opacity: 0.5; stroke: #ff7575; stroke-linejoin: miter"/> +" clip-path="url(#p31d396b544)" style="fill: #ff7575; opacity: 0.5; stroke: #ff7575; stroke-linejoin: miter"/> @@ -27988,12 +27988,12 @@ L 392.914825 369.248174 L 393.184623 369.250201 L 393.45442 369.251396 L 393.724217 369.251788 -" clip-path="url(#p03ca37afdf)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p31d396b544)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p31d396b544)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28011,7 +28011,7 @@ L 422.92437 378.465882 L 422.92437 359.830588 L 399.478992 359.830588 z -" clip-path="url(#p135c201e2d)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> +" clip-path="url(#p22d8ff3412)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> @@ -28096,12 +28096,12 @@ L 421.049279 369.254431 L 421.319076 369.252949 L 421.588874 369.252075 L 421.858671 369.251788 -" clip-path="url(#p135c201e2d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p22d8ff3412)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p22d8ff3412)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28119,7 +28119,7 @@ L 451.058824 378.465882 L 451.058824 359.830588 L 427.613445 359.830588 z -" clip-path="url(#p88c6dce251)" style="fill: #ff6161; opacity: 0.5; stroke: #ff6161; stroke-linejoin: miter"/> +" clip-path="url(#pc755ddab7c)" style="fill: #ff6161; opacity: 0.5; stroke: #ff6161; stroke-linejoin: miter"/> @@ -28204,12 +28204,12 @@ L 449.183733 369.253163 L 449.45353 369.252392 L 449.723327 369.251937 L 449.993125 369.251788 -" clip-path="url(#p88c6dce251)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc755ddab7c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc755ddab7c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28227,7 +28227,7 @@ L 479.193277 378.465882 L 479.193277 359.830588 L 455.747899 359.830588 z -" clip-path="url(#p639763f5c3)" style="fill: #ff5d5d; opacity: 0.5; stroke: #ff5d5d; stroke-linejoin: miter"/> +" clip-path="url(#pae26406531)" style="fill: #ff5d5d; opacity: 0.5; stroke: #ff5d5d; stroke-linejoin: miter"/> @@ -28312,12 +28312,12 @@ L 477.318187 369.25178 L 477.587984 369.251785 L 477.857781 369.251787 L 478.127578 369.251788 -" clip-path="url(#p639763f5c3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pae26406531)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pae26406531)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28335,7 +28335,7 @@ L 507.327731 378.465882 L 507.327731 359.830588 L 483.882353 359.830588 z -" clip-path="url(#p41a991b70e)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p6e7fbb1232)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -28420,12 +28420,12 @@ L 505.45264 369.24685 L 505.722438 369.249619 L 505.992235 369.251253 L 506.262032 369.251788 -" clip-path="url(#p41a991b70e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6e7fbb1232)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6e7fbb1232)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28443,7 +28443,7 @@ L 535.462185 378.465882 L 535.462185 359.830588 L 512.016807 359.830588 z -" clip-path="url(#pb0485dc74f)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> +" clip-path="url(#p6ae44873d6)" style="fill: #ffb5b5; opacity: 0.5; stroke: #ffb5b5; stroke-linejoin: miter"/> @@ -28528,12 +28528,12 @@ L 533.587094 369.250883 L 533.856891 369.251391 L 534.126689 369.25169 L 534.396486 369.251788 -" clip-path="url(#pb0485dc74f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6ae44873d6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6ae44873d6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28551,7 +28551,7 @@ L 563.596639 378.465882 L 563.596639 359.830588 L 540.151261 359.830588 z -" clip-path="url(#p7155266994)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> +" clip-path="url(#paab7cdca3d)" style="fill: #ffa5a5; opacity: 0.5; stroke: #ffa5a5; stroke-linejoin: miter"/> @@ -28636,12 +28636,12 @@ L 561.721548 369.255898 L 561.991345 369.253593 L 562.261142 369.252234 L 562.53094 369.251788 -" clip-path="url(#p7155266994)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paab7cdca3d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paab7cdca3d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28659,7 +28659,7 @@ L 591.731092 378.465882 L 591.731092 359.830588 L 568.285714 359.830588 z -" clip-path="url(#pca900533b1)" style="fill: #e1e1ff; opacity: 0.5; stroke: #e1e1ff; stroke-linejoin: miter"/> +" clip-path="url(#p50875204f8)" style="fill: #e1e1ff; opacity: 0.5; stroke: #e1e1ff; stroke-linejoin: miter"/> @@ -28744,12 +28744,12 @@ L 589.856002 369.254953 L 590.125799 369.253178 L 590.395596 369.252132 L 590.665393 369.251788 -" clip-path="url(#pca900533b1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p50875204f8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p50875204f8)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28767,7 +28767,7 @@ L 619.865546 378.465882 L 619.865546 359.830588 L 596.420168 359.830588 z -" clip-path="url(#pde7ed88ea4)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p783b114052)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -28852,12 +28852,12 @@ L 617.990456 369.25581 L 618.260253 369.253554 L 618.53005 369.252225 L 618.799847 369.251788 -" clip-path="url(#pde7ed88ea4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p783b114052)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p783b114052)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28875,7 +28875,7 @@ L 113.445378 400.828235 L 113.445378 382.192941 L 90 382.192941 z -" clip-path="url(#pa1cc92e239)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> +" clip-path="url(#p1143f5d8a3)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> @@ -28960,12 +28960,12 @@ L 111.570287 392.679561 L 111.840085 392.6747 L 112.109882 392.671833 L 112.379679 392.670893 -" clip-path="url(#pa1cc92e239)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1143f5d8a3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1143f5d8a3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -28983,7 +28983,7 @@ L 141.579832 400.828235 L 141.579832 382.192941 L 118.134454 382.192941 z -" clip-path="url(#p51eae4916d)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> +" clip-path="url(#p0c0b5e0969)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> @@ -29068,12 +29068,12 @@ L 139.704741 392.683622 L 139.974538 392.676484 L 140.244336 392.672274 L 140.514133 392.670893 -" clip-path="url(#p51eae4916d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0c0b5e0969)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0c0b5e0969)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29091,7 +29091,7 @@ L 169.714286 400.828235 L 169.714286 382.192941 L 146.268908 382.192941 z -" clip-path="url(#pd23268f27e)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> +" clip-path="url(#pdb613b5c02)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> @@ -29176,12 +29176,12 @@ L 167.839195 392.690581 L 168.108992 392.67954 L 168.378789 392.673029 L 168.648587 392.670893 -" clip-path="url(#pd23268f27e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdb613b5c02)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdb613b5c02)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29199,7 +29199,7 @@ L 197.848739 400.828235 L 197.848739 382.192941 L 174.403361 382.192941 z -" clip-path="url(#p246adfd2f1)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> +" clip-path="url(#pcc74bc77a8)" style="fill: #d5d5ff; opacity: 0.5; stroke: #d5d5ff; stroke-linejoin: miter"/> @@ -29284,12 +29284,12 @@ L 195.973649 392.681864 L 196.243446 392.675711 L 196.513243 392.672083 L 196.78304 392.670893 -" clip-path="url(#p246adfd2f1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcc74bc77a8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pcc74bc77a8)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29307,7 +29307,7 @@ L 225.983193 400.828235 L 225.983193 382.192941 L 202.537815 382.192941 z -" clip-path="url(#p6b69215851)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> +" clip-path="url(#p1783e543ea)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> @@ -29392,12 +29392,12 @@ L 224.108103 392.685461 L 224.3779 392.677291 L 224.647697 392.672473 L 224.917494 392.670893 -" clip-path="url(#p6b69215851)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1783e543ea)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1783e543ea)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29415,7 +29415,7 @@ L 254.117647 400.828235 L 254.117647 382.192941 L 230.672269 382.192941 z -" clip-path="url(#p5ca6990613)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> +" clip-path="url(#pe88cb4ec76)" style="fill: #8989ff; opacity: 0.5; stroke: #8989ff; stroke-linejoin: miter"/> @@ -29500,12 +29500,12 @@ L 252.242556 392.694649 L 252.512354 392.681327 L 252.782151 392.67347 L 253.051948 392.670893 -" clip-path="url(#p5ca6990613)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe88cb4ec76)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe88cb4ec76)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29523,7 +29523,7 @@ L 282.252101 400.828235 L 282.252101 382.192941 L 258.806723 382.192941 z -" clip-path="url(#pcfb0cdc4ab)" style="fill: #e1e1ff; opacity: 0.5; stroke: #e1e1ff; stroke-linejoin: miter"/> +" clip-path="url(#pd86cfd712e)" style="fill: #e1e1ff; opacity: 0.5; stroke: #e1e1ff; stroke-linejoin: miter"/> @@ -29608,12 +29608,12 @@ L 280.37701 392.674501 L 280.646807 392.672478 L 280.916605 392.671284 L 281.186402 392.670893 -" clip-path="url(#pcfb0cdc4ab)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd86cfd712e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd86cfd712e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29631,7 +29631,7 @@ L 310.386555 400.828235 L 310.386555 382.192941 L 286.941176 382.192941 z -" clip-path="url(#pe6179c6d71)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> +" clip-path="url(#p27fb0fb4e8)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> @@ -29716,12 +29716,12 @@ L 308.511464 392.683464 L 308.781261 392.676414 L 309.051058 392.672256 L 309.320856 392.670893 -" clip-path="url(#pe6179c6d71)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p27fb0fb4e8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p27fb0fb4e8)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29739,7 +29739,7 @@ L 338.521008 400.828235 L 338.521008 382.192941 L 315.07563 382.192941 z -" clip-path="url(#pd448add62a)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> +" clip-path="url(#p4839c36354)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> @@ -29824,12 +29824,12 @@ L 336.645918 392.685797 L 336.915715 392.677439 L 337.185512 392.67251 L 337.455309 392.670893 -" clip-path="url(#pd448add62a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4839c36354)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4839c36354)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29847,7 +29847,7 @@ L 366.655462 400.828235 L 366.655462 382.192941 L 343.210084 382.192941 z -" clip-path="url(#p446f39a24f)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p6d84e1b8ce)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -29932,12 +29932,12 @@ L 364.780372 392.680705 L 365.050169 392.675202 L 365.319966 392.671957 L 365.589763 392.670893 -" clip-path="url(#p446f39a24f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6d84e1b8ce)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6d84e1b8ce)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -29955,7 +29955,7 @@ L 394.789916 400.828235 L 394.789916 382.192941 L 371.344538 382.192941 z -" clip-path="url(#peaee05f51e)" style="fill: #ffd1d1; opacity: 0.5; stroke: #ffd1d1; stroke-linejoin: miter"/> +" clip-path="url(#p5d7aeb56c5)" style="fill: #ffd1d1; opacity: 0.5; stroke: #ffd1d1; stroke-linejoin: miter"/> @@ -30040,12 +30040,12 @@ L 392.914825 392.670642 L 393.184623 392.670783 L 393.45442 392.670866 L 393.724217 392.670893 -" clip-path="url(#peaee05f51e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5d7aeb56c5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5d7aeb56c5)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30063,7 +30063,7 @@ L 422.92437 400.828235 L 422.92437 382.192941 L 399.478992 382.192941 z -" clip-path="url(#p3e39b45530)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> +" clip-path="url(#pa081830c3b)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> @@ -30148,12 +30148,12 @@ L 421.049279 392.67871 L 421.319076 392.674326 L 421.588874 392.671741 L 421.858671 392.670893 -" clip-path="url(#p3e39b45530)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa081830c3b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa081830c3b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30171,7 +30171,7 @@ L 451.058824 400.828235 L 451.058824 382.192941 L 427.613445 382.192941 z -" clip-path="url(#p5146197f30)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> +" clip-path="url(#peb9fb04617)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> @@ -30256,12 +30256,12 @@ L 449.183733 392.658006 L 449.45353 392.665233 L 449.723327 392.669495 L 449.993125 392.670893 -" clip-path="url(#p5146197f30)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#peb9fb04617)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#peb9fb04617)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30279,7 +30279,7 @@ L 479.193277 400.828235 L 479.193277 382.192941 L 455.747899 382.192941 z -" clip-path="url(#p92ccf12f44)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> +" clip-path="url(#p82399adbd8)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> @@ -30364,12 +30364,12 @@ L 477.318187 392.694224 L 477.587984 392.68114 L 477.857781 392.673424 L 478.127578 392.670893 -" clip-path="url(#p92ccf12f44)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p82399adbd8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p82399adbd8)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30387,7 +30387,7 @@ L 507.327731 400.828235 L 507.327731 382.192941 L 483.882353 382.192941 z -" clip-path="url(#pafa5d056b5)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p5459d90bd1)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -30472,12 +30472,12 @@ L 505.45264 392.643459 L 505.722438 392.658844 L 505.992235 392.667917 L 506.262032 392.670893 -" clip-path="url(#pafa5d056b5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5459d90bd1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5459d90bd1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30495,7 +30495,7 @@ L 535.462185 400.828235 L 535.462185 382.192941 L 512.016807 382.192941 z -" clip-path="url(#p5ce99dbdcf)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> +" clip-path="url(#p057908711f)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> @@ -30580,12 +30580,12 @@ L 533.587094 392.679005 L 533.856891 392.674455 L 534.126689 392.671773 L 534.396486 392.670893 -" clip-path="url(#p5ce99dbdcf)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p057908711f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p057908711f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30603,7 +30603,7 @@ L 563.596639 400.828235 L 563.596639 382.192941 L 540.151261 382.192941 z -" clip-path="url(#p2e6ebf0bf7)" style="fill: #ffc9c9; opacity: 0.5; stroke: #ffc9c9; stroke-linejoin: miter"/> +" clip-path="url(#p0236f58d31)" style="fill: #ffc9c9; opacity: 0.5; stroke: #ffc9c9; stroke-linejoin: miter"/> @@ -30688,12 +30688,12 @@ L 561.721548 392.6683 L 561.991345 392.669754 L 562.261142 392.670612 L 562.53094 392.670893 -" clip-path="url(#p2e6ebf0bf7)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0236f58d31)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p0236f58d31)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30711,7 +30711,7 @@ L 591.731092 400.828235 L 591.731092 382.192941 L 568.285714 382.192941 z -" clip-path="url(#p3955840a10)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#p5f6e910c37)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -30796,12 +30796,12 @@ L 589.856002 392.672609 L 590.125799 392.671647 L 590.395596 392.671079 L 590.665393 392.670893 -" clip-path="url(#p3955840a10)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5f6e910c37)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5f6e910c37)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30819,7 +30819,7 @@ L 619.865546 400.828235 L 619.865546 382.192941 L 596.420168 382.192941 z -" clip-path="url(#pc7120b9a03)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> +" clip-path="url(#pf0c9d28633)" style="fill: #fff1f1; opacity: 0.5; stroke: #fff1f1; stroke-linejoin: miter"/> @@ -30904,12 +30904,12 @@ L 617.990456 392.667545 L 618.260253 392.669422 L 618.53005 392.67053 L 618.799847 392.670893 -" clip-path="url(#pc7120b9a03)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf0c9d28633)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pf0c9d28633)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -30927,7 +30927,7 @@ L 113.445378 423.190588 L 113.445378 404.555294 L 90 404.555294 z -" clip-path="url(#pcab0cd8681)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> +" clip-path="url(#pdfdd0d9204)" style="fill: #f1f1ff; opacity: 0.5; stroke: #f1f1ff; stroke-linejoin: miter"/> @@ -31012,12 +31012,12 @@ L 111.570287 415.476795 L 111.840085 415.46583 L 112.109882 415.459363 L 112.379679 415.457242 -" clip-path="url(#pcab0cd8681)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdfdd0d9204)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pdfdd0d9204)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31035,7 +31035,7 @@ L 141.579832 423.190588 L 141.579832 404.555294 L 118.134454 404.555294 z -" clip-path="url(#pc2e7d82265)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#pd91113d934)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -31120,12 +31120,12 @@ L 139.704741 415.45785 L 139.974538 415.457509 L 140.244336 415.457308 L 140.514133 415.457242 -" clip-path="url(#pc2e7d82265)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd91113d934)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd91113d934)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31143,7 +31143,7 @@ L 169.714286 423.190588 L 169.714286 404.555294 L 146.268908 404.555294 z -" clip-path="url(#p339dda21e6)" style="fill: #2d2dff; opacity: 0.5; stroke: #2d2dff; stroke-linejoin: miter"/> +" clip-path="url(#p418b6bf97a)" style="fill: #2d2dff; opacity: 0.5; stroke: #2d2dff; stroke-linejoin: miter"/> @@ -31228,12 +31228,12 @@ L 167.839195 415.480716 L 168.108992 415.467552 L 168.378789 415.459789 L 168.648587 415.457242 -" clip-path="url(#p339dda21e6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p418b6bf97a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p418b6bf97a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31251,7 +31251,7 @@ L 197.848739 423.190588 L 197.848739 404.555294 L 174.403361 404.555294 z -" clip-path="url(#pe6f72e73fe)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> +" clip-path="url(#paba838a847)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> @@ -31336,12 +31336,12 @@ L 195.973649 415.468738 L 196.243446 415.462291 L 196.513243 415.458489 L 196.78304 415.457242 -" clip-path="url(#pe6f72e73fe)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paba838a847)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paba838a847)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31359,7 +31359,7 @@ L 225.983193 423.190588 L 225.983193 404.555294 L 202.537815 404.555294 z -" clip-path="url(#p65d2056300)" style="fill: #4949ff; opacity: 0.5; stroke: #4949ff; stroke-linejoin: miter"/> +" clip-path="url(#pd7afcf92e6)" style="fill: #4949ff; opacity: 0.5; stroke: #4949ff; stroke-linejoin: miter"/> @@ -31444,12 +31444,12 @@ L 224.108103 415.470715 L 224.3779 415.463159 L 224.647697 415.458704 L 224.917494 415.457242 -" clip-path="url(#p65d2056300)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd7afcf92e6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pd7afcf92e6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31467,7 +31467,7 @@ L 254.117647 423.190588 L 254.117647 404.555294 L 230.672269 404.555294 z -" clip-path="url(#p57b9bf43b9)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> +" clip-path="url(#pe8a3c09467)" style="fill: #d9d9ff; opacity: 0.5; stroke: #d9d9ff; stroke-linejoin: miter"/> @@ -31552,12 +31552,12 @@ L 252.242556 415.460686 L 252.512354 415.458755 L 252.782151 415.457616 L 253.051948 415.457242 -" clip-path="url(#p57b9bf43b9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe8a3c09467)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe8a3c09467)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31575,7 +31575,7 @@ L 282.252101 423.190588 L 282.252101 404.555294 L 258.806723 404.555294 z -" clip-path="url(#pa8dcf6bf44)" style="fill: #ffc1c1; opacity: 0.5; stroke: #ffc1c1; stroke-linejoin: miter"/> +" clip-path="url(#p429bee071a)" style="fill: #ffc1c1; opacity: 0.5; stroke: #ffc1c1; stroke-linejoin: miter"/> @@ -31660,12 +31660,12 @@ L 280.37701 415.450029 L 280.646807 415.454074 L 280.916605 415.45646 L 281.186402 415.457242 -" clip-path="url(#pa8dcf6bf44)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p429bee071a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p429bee071a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31683,7 +31683,7 @@ L 310.386555 423.190588 L 310.386555 404.555294 L 286.941176 404.555294 z -" clip-path="url(#pba0d58a58a)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> +" clip-path="url(#p3752febef1)" style="fill: #fff9f9; opacity: 0.5; stroke: #fff9f9; stroke-linejoin: miter"/> @@ -31768,12 +31768,12 @@ L 308.511464 415.458474 L 308.781261 415.457783 L 309.051058 415.457376 L 309.320856 415.457242 -" clip-path="url(#pba0d58a58a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3752febef1)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3752febef1)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31791,7 +31791,7 @@ L 338.521008 423.190588 L 338.521008 404.555294 L 315.07563 404.555294 z -" clip-path="url(#p85e48c783e)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> +" clip-path="url(#p874979d5a9)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> @@ -31876,12 +31876,12 @@ L 336.645918 415.473255 L 336.915715 415.464275 L 337.185512 415.458979 L 337.455309 415.457242 -" clip-path="url(#p85e48c783e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p874979d5a9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p874979d5a9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -31899,7 +31899,7 @@ L 366.655462 423.190588 L 366.655462 404.555294 L 343.210084 404.555294 z -" clip-path="url(#p38877f9dec)" style="fill: #a9a9ff; opacity: 0.5; stroke: #a9a9ff; stroke-linejoin: miter"/> +" clip-path="url(#pa78f98e917)" style="fill: #a9a9ff; opacity: 0.5; stroke: #a9a9ff; stroke-linejoin: miter"/> @@ -31984,12 +31984,12 @@ L 364.780372 415.464478 L 365.050169 415.46042 L 365.319966 415.458027 L 365.589763 415.457242 -" clip-path="url(#p38877f9dec)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa78f98e917)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa78f98e917)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32007,7 +32007,7 @@ L 394.789916 423.190588 L 394.789916 404.555294 L 371.344538 404.555294 z -" clip-path="url(#p7cc3fe753b)" style="fill: #ffd5d5; opacity: 0.5; stroke: #ffd5d5; stroke-linejoin: miter"/> +" clip-path="url(#p445cc6c0e4)" style="fill: #ffd5d5; opacity: 0.5; stroke: #ffd5d5; stroke-linejoin: miter"/> @@ -32092,12 +32092,12 @@ L 392.914825 415.449228 L 393.184623 415.453723 L 393.45442 415.456373 L 393.724217 415.457242 -" clip-path="url(#p7cc3fe753b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p445cc6c0e4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p445cc6c0e4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32115,7 +32115,7 @@ L 422.92437 423.190588 L 422.92437 404.555294 L 399.478992 404.555294 z -" clip-path="url(#pe678e41556)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#p4c2d7576d4)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -32200,12 +32200,12 @@ L 421.049279 415.46869 L 421.319076 415.46227 L 421.588874 415.458484 L 421.858671 415.457242 -" clip-path="url(#pe678e41556)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4c2d7576d4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4c2d7576d4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32223,7 +32223,7 @@ L 451.058824 423.190588 L 451.058824 404.555294 L 427.613445 404.555294 z -" clip-path="url(#paae62c5eae)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p54ed2482c4)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -32308,12 +32308,12 @@ L 449.183733 415.449992 L 449.45353 415.454058 L 449.723327 415.456456 L 449.993125 415.457242 -" clip-path="url(#paae62c5eae)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p54ed2482c4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p54ed2482c4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32331,7 +32331,7 @@ L 479.193277 423.190588 L 479.193277 404.555294 L 455.747899 404.555294 z -" clip-path="url(#pa5b3daa724)" style="fill: #ff9999; opacity: 0.5; stroke: #ff9999; stroke-linejoin: miter"/> +" clip-path="url(#pea57e52310)" style="fill: #ff9999; opacity: 0.5; stroke: #ff9999; stroke-linejoin: miter"/> @@ -32416,12 +32416,12 @@ L 477.318187 415.457608 L 477.587984 415.457403 L 477.857781 415.457282 L 478.127578 415.457242 -" clip-path="url(#pa5b3daa724)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pea57e52310)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pea57e52310)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32439,7 +32439,7 @@ L 507.327731 423.190588 L 507.327731 404.555294 L 483.882353 404.555294 z -" clip-path="url(#p25fd40c0aa)" style="fill: #ff6565; opacity: 0.5; stroke: #ff6565; stroke-linejoin: miter"/> +" clip-path="url(#pe967a67e7b)" style="fill: #ff6565; opacity: 0.5; stroke: #ff6565; stroke-linejoin: miter"/> @@ -32524,12 +32524,12 @@ L 505.45264 415.446837 L 505.722438 415.452672 L 505.992235 415.456113 L 506.262032 415.457242 -" clip-path="url(#p25fd40c0aa)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe967a67e7b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe967a67e7b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32547,7 +32547,7 @@ L 535.462185 423.190588 L 535.462185 404.555294 L 512.016807 404.555294 z -" clip-path="url(#p1924177a5f)" style="fill: #ff6d6d; opacity: 0.5; stroke: #ff6d6d; stroke-linejoin: miter"/> +" clip-path="url(#p2f1a92864a)" style="fill: #ff6d6d; opacity: 0.5; stroke: #ff6d6d; stroke-linejoin: miter"/> @@ -32632,12 +32632,12 @@ L 533.587094 415.454417 L 533.856891 415.456001 L 534.126689 415.456936 L 534.396486 415.457242 -" clip-path="url(#p1924177a5f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2f1a92864a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p2f1a92864a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32655,7 +32655,7 @@ L 563.596639 423.190588 L 563.596639 404.555294 L 540.151261 404.555294 z -" clip-path="url(#pe4f475e0bc)" style="fill: #ff9595; opacity: 0.5; stroke: #ff9595; stroke-linejoin: miter"/> +" clip-path="url(#p00eb9e3f1c)" style="fill: #ff9595; opacity: 0.5; stroke: #ff9595; stroke-linejoin: miter"/> @@ -32740,12 +32740,12 @@ L 561.721548 415.462082 L 561.991345 415.459368 L 562.261142 415.457767 L 562.53094 415.457242 -" clip-path="url(#pe4f475e0bc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p00eb9e3f1c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p00eb9e3f1c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32763,7 +32763,7 @@ L 591.731092 423.190588 L 591.731092 404.555294 L 568.285714 404.555294 z -" clip-path="url(#p45b464a679)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> +" clip-path="url(#p328d2eafce)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> @@ -32848,12 +32848,12 @@ L 589.856002 415.465855 L 590.125799 415.461025 L 590.395596 415.458177 L 590.665393 415.457242 -" clip-path="url(#p45b464a679)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p328d2eafce)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p328d2eafce)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32871,7 +32871,7 @@ L 619.865546 423.190588 L 619.865546 404.555294 L 596.420168 404.555294 z -" clip-path="url(#p720c15bc52)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> +" clip-path="url(#p6ce50caf14)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> @@ -32956,12 +32956,12 @@ L 617.990456 415.460143 L 618.260253 415.458516 L 618.53005 415.457557 L 618.799847 415.457242 -" clip-path="url(#p720c15bc52)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6ce50caf14)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6ce50caf14)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -32979,7 +32979,7 @@ L 113.445378 445.552941 L 113.445378 426.917647 L 90 426.917647 z -" clip-path="url(#p477467a738)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> +" clip-path="url(#p16bd4adba2)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> @@ -33064,12 +33064,12 @@ L 111.570287 439.308133 L 111.840085 439.306067 L 112.109882 439.304849 L 112.379679 439.304449 -" clip-path="url(#p477467a738)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p16bd4adba2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p16bd4adba2)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33087,7 +33087,7 @@ L 141.579832 445.552941 L 141.579832 426.917647 L 118.134454 426.917647 z -" clip-path="url(#pfb9caf8f44)" style="fill: #5d5dff; opacity: 0.5; stroke: #5d5dff; stroke-linejoin: miter"/> +" clip-path="url(#p58206460f4)" style="fill: #5d5dff; opacity: 0.5; stroke: #5d5dff; stroke-linejoin: miter"/> @@ -33172,12 +33172,12 @@ L 139.704741 439.317069 L 139.974538 439.309992 L 140.244336 439.305818 L 140.514133 439.304449 -" clip-path="url(#pfb9caf8f44)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p58206460f4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p58206460f4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33195,7 +33195,7 @@ L 169.714286 445.552941 L 169.714286 426.917647 L 146.268908 426.917647 z -" clip-path="url(#pdd7c4ed883)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> +" clip-path="url(#pc6802d4255)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> @@ -33280,12 +33280,12 @@ L 167.839195 439.313623 L 168.108992 439.308478 L 168.378789 439.305444 L 168.648587 439.304449 -" clip-path="url(#pdd7c4ed883)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc6802d4255)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc6802d4255)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33303,7 +33303,7 @@ L 197.848739 445.552941 L 197.848739 426.917647 L 174.403361 426.917647 z -" clip-path="url(#p19d5b45545)" style="fill: #5d5dff; opacity: 0.5; stroke: #5d5dff; stroke-linejoin: miter"/> +" clip-path="url(#p037001c34e)" style="fill: #5d5dff; opacity: 0.5; stroke: #5d5dff; stroke-linejoin: miter"/> @@ -33388,12 +33388,12 @@ L 195.973649 439.315047 L 196.243446 439.309103 L 196.513243 439.305599 L 196.78304 439.304449 -" clip-path="url(#p19d5b45545)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p037001c34e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p037001c34e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33411,7 +33411,7 @@ L 225.983193 445.552941 L 225.983193 426.917647 L 202.537815 426.917647 z -" clip-path="url(#p594053c304)" style="fill: #1919ff; opacity: 0.5; stroke: #1919ff; stroke-linejoin: miter"/> +" clip-path="url(#pb7a5d6a0b4)" style="fill: #1919ff; opacity: 0.5; stroke: #1919ff; stroke-linejoin: miter"/> @@ -33496,12 +33496,12 @@ L 224.108103 439.314875 L 224.3779 439.309028 L 224.647697 439.30558 L 224.917494 439.304449 -" clip-path="url(#p594053c304)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb7a5d6a0b4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb7a5d6a0b4)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33519,7 +33519,7 @@ L 254.117647 445.552941 L 254.117647 426.917647 L 230.672269 426.917647 z -" clip-path="url(#p1bff6cd4ce)" style="fill: #4545ff; opacity: 0.5; stroke: #4545ff; stroke-linejoin: miter"/> +" clip-path="url(#p8e793fa756)" style="fill: #4545ff; opacity: 0.5; stroke: #4545ff; stroke-linejoin: miter"/> @@ -33604,12 +33604,12 @@ L 252.242556 439.317818 L 252.512354 439.31032 L 252.782151 439.305899 L 253.051948 439.304449 -" clip-path="url(#p1bff6cd4ce)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8e793fa756)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8e793fa756)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33627,7 +33627,7 @@ L 282.252101 445.552941 L 282.252101 426.917647 L 258.806723 426.917647 z -" clip-path="url(#pf4c515989d)" style="fill: #4949ff; opacity: 0.5; stroke: #4949ff; stroke-linejoin: miter"/> +" clip-path="url(#pfa777b0897)" style="fill: #4949ff; opacity: 0.5; stroke: #4949ff; stroke-linejoin: miter"/> @@ -33712,12 +33712,12 @@ L 280.37701 439.314713 L 280.646807 439.308957 L 280.916605 439.305562 L 281.186402 439.304449 -" clip-path="url(#pf4c515989d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfa777b0897)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfa777b0897)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33735,7 +33735,7 @@ L 310.386555 445.552941 L 310.386555 426.917647 L 286.941176 426.917647 z -" clip-path="url(#p41bb6ac8fb)" style="fill: #1111ff; opacity: 0.5; stroke: #1111ff; stroke-linejoin: miter"/> +" clip-path="url(#p8f112aaef9)" style="fill: #1111ff; opacity: 0.5; stroke: #1111ff; stroke-linejoin: miter"/> @@ -33820,12 +33820,12 @@ L 308.511464 439.316418 L 308.781261 439.309706 L 309.051058 439.305747 L 309.320856 439.304449 -" clip-path="url(#p41bb6ac8fb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8f112aaef9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8f112aaef9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33843,7 +33843,7 @@ L 338.521008 445.552941 L 338.521008 426.917647 L 315.07563 426.917647 z -" clip-path="url(#pd70e6a6209)" style="fill: #7979ff; opacity: 0.5; stroke: #7979ff; stroke-linejoin: miter"/> +" clip-path="url(#pfa6a1b5db9)" style="fill: #7979ff; opacity: 0.5; stroke: #7979ff; stroke-linejoin: miter"/> @@ -33928,12 +33928,12 @@ L 336.645918 439.311237 L 336.915715 439.30743 L 337.185512 439.305185 L 337.455309 439.304449 -" clip-path="url(#pd70e6a6209)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfa6a1b5db9)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfa6a1b5db9)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -33951,7 +33951,7 @@ L 366.655462 445.552941 L 366.655462 426.917647 L 343.210084 426.917647 z -" clip-path="url(#p356c0af8e3)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> +" clip-path="url(#pad3dd23165)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> @@ -34036,12 +34036,12 @@ L 364.780372 439.304844 L 365.050169 439.304622 L 365.319966 439.304492 L 365.589763 439.304449 -" clip-path="url(#p356c0af8e3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pad3dd23165)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pad3dd23165)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34059,7 +34059,7 @@ L 394.789916 445.552941 L 394.789916 426.917647 L 371.344538 426.917647 z -" clip-path="url(#p4da39ac640)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> +" clip-path="url(#p4239c906fd)" style="fill: #ff9d9d; opacity: 0.5; stroke: #ff9d9d; stroke-linejoin: miter"/> @@ -34144,12 +34144,12 @@ L 392.914825 439.295674 L 393.184623 439.300595 L 393.45442 439.303497 L 393.724217 439.304449 -" clip-path="url(#p4da39ac640)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4239c906fd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4239c906fd)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34167,7 +34167,7 @@ L 422.92437 445.552941 L 422.92437 426.917647 L 399.478992 426.917647 z -" clip-path="url(#p49d66f28e4)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> +" clip-path="url(#pea01b2ccf6)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> @@ -34252,12 +34252,12 @@ L 421.049279 439.313554 L 421.319076 439.308448 L 421.588874 439.305437 L 421.858671 439.304449 -" clip-path="url(#p49d66f28e4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pea01b2ccf6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pea01b2ccf6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34275,7 +34275,7 @@ L 451.058824 445.552941 L 451.058824 426.917647 L 427.613445 426.917647 z -" clip-path="url(#paa1164f8c4)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> +" clip-path="url(#p9e286812c2)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> @@ -34360,12 +34360,12 @@ L 449.183733 439.296166 L 449.45353 439.300811 L 449.723327 439.30355 L 449.993125 439.304449 -" clip-path="url(#paa1164f8c4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9e286812c2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p9e286812c2)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34383,7 +34383,7 @@ L 479.193277 445.552941 L 479.193277 426.917647 L 455.747899 426.917647 z -" clip-path="url(#p38f6c08323)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p088ba6d382)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -34468,12 +34468,12 @@ L 477.318187 439.315477 L 477.587984 439.309292 L 477.857781 439.305645 L 478.127578 439.304449 -" clip-path="url(#p38f6c08323)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p088ba6d382)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p088ba6d382)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34491,7 +34491,7 @@ L 507.327731 445.552941 L 507.327731 426.917647 L 483.882353 426.917647 z -" clip-path="url(#p6e3500356b)" style="fill: #ffd5d5; opacity: 0.5; stroke: #ffd5d5; stroke-linejoin: miter"/> +" clip-path="url(#p397667c152)" style="fill: #ffd5d5; opacity: 0.5; stroke: #ffd5d5; stroke-linejoin: miter"/> @@ -34576,12 +34576,12 @@ L 505.45264 439.301718 L 505.722438 439.303249 L 505.992235 439.304153 L 506.262032 439.304449 -" clip-path="url(#p6e3500356b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p397667c152)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p397667c152)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34599,7 +34599,7 @@ L 535.462185 445.552941 L 535.462185 426.917647 L 512.016807 426.917647 z -" clip-path="url(#pe9ed4b5568)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#p3aa24a02c2)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -34684,12 +34684,12 @@ L 533.587094 439.310185 L 533.856891 439.306968 L 534.126689 439.305071 L 534.396486 439.304449 -" clip-path="url(#pe9ed4b5568)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3aa24a02c2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3aa24a02c2)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34707,7 +34707,7 @@ L 563.596639 445.552941 L 563.596639 426.917647 L 540.151261 426.917647 z -" clip-path="url(#pd4dd9965da)" style="fill: #ff7575; opacity: 0.5; stroke: #ff7575; stroke-linejoin: miter"/> +" clip-path="url(#pc692e1d072)" style="fill: #ff7575; opacity: 0.5; stroke: #ff7575; stroke-linejoin: miter"/> @@ -34792,12 +34792,12 @@ L 561.721548 439.299768 L 561.991345 439.302393 L 562.261142 439.303941 L 562.53094 439.304449 -" clip-path="url(#pd4dd9965da)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc692e1d072)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc692e1d072)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34815,7 +34815,7 @@ L 591.731092 445.552941 L 591.731092 426.917647 L 568.285714 426.917647 z -" clip-path="url(#pab7cd0c028)" style="fill: #ff6565; opacity: 0.5; stroke: #ff6565; stroke-linejoin: miter"/> +" clip-path="url(#p4bf672dc8a)" style="fill: #ff6565; opacity: 0.5; stroke: #ff6565; stroke-linejoin: miter"/> @@ -34900,12 +34900,12 @@ L 589.856002 439.291944 L 590.125799 439.298957 L 590.395596 439.303092 L 590.665393 439.304449 -" clip-path="url(#pab7cd0c028)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4bf672dc8a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4bf672dc8a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -34923,7 +34923,7 @@ L 619.865546 445.552941 L 619.865546 426.917647 L 596.420168 426.917647 z -" clip-path="url(#p5c17b5836a)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#pc82915499e)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -35008,12 +35008,12 @@ L 617.990456 439.296575 L 618.260253 439.300991 L 618.53005 439.303595 L 618.799847 439.304449 -" clip-path="url(#p5c17b5836a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc82915499e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc82915499e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35031,7 +35031,7 @@ L 113.445378 467.915294 L 113.445378 449.28 L 90 449.28 z -" clip-path="url(#pfcd64a4992)" style="fill: #7d7dff; opacity: 0.5; stroke: #7d7dff; stroke-linejoin: miter"/> +" clip-path="url(#p28cfcb26bc)" style="fill: #7d7dff; opacity: 0.5; stroke: #7d7dff; stroke-linejoin: miter"/> @@ -35116,12 +35116,12 @@ L 111.570287 458.537197 L 111.840085 458.530534 L 112.109882 458.526604 L 112.379679 458.525316 -" clip-path="url(#pfcd64a4992)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p28cfcb26bc)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p28cfcb26bc)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35139,7 +35139,7 @@ L 141.579832 467.915294 L 141.579832 449.28 L 118.134454 449.28 z -" clip-path="url(#pcbb50b34b4)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#pa226906286)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -35224,12 +35224,12 @@ L 139.704741 458.533721 L 139.974538 458.529007 L 140.244336 458.526227 L 140.514133 458.525316 -" clip-path="url(#pcbb50b34b4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa226906286)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa226906286)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35247,7 +35247,7 @@ L 169.714286 467.915294 L 169.714286 449.28 L 146.268908 449.28 z -" clip-path="url(#p9d71c3e432)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> +" clip-path="url(#p07f97a105f)" style="fill: #b5b5ff; opacity: 0.5; stroke: #b5b5ff; stroke-linejoin: miter"/> @@ -35332,12 +35332,12 @@ L 167.839195 458.544241 L 168.108992 458.533628 L 168.378789 458.527369 L 168.648587 458.525316 -" clip-path="url(#p9d71c3e432)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p07f97a105f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p07f97a105f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35355,7 +35355,7 @@ L 197.848739 467.915294 L 197.848739 449.28 L 174.403361 449.28 z -" clip-path="url(#paab8e23e0a)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> +" clip-path="url(#p185999484f)" style="fill: #d1d1ff; opacity: 0.5; stroke: #d1d1ff; stroke-linejoin: miter"/> @@ -35440,12 +35440,12 @@ L 195.973649 458.529259 L 196.243446 458.527048 L 196.513243 458.525743 L 196.78304 458.525316 -" clip-path="url(#paab8e23e0a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p185999484f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p185999484f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35463,7 +35463,7 @@ L 225.983193 467.915294 L 225.983193 449.28 L 202.537815 449.28 z -" clip-path="url(#p60df48ef90)" style="fill: #6161ff; opacity: 0.5; stroke: #6161ff; stroke-linejoin: miter"/> +" clip-path="url(#pfcc8f838ad)" style="fill: #6161ff; opacity: 0.5; stroke: #6161ff; stroke-linejoin: miter"/> @@ -35548,12 +35548,12 @@ L 224.108103 458.544783 L 224.3779 458.533866 L 224.647697 458.527427 L 224.917494 458.525316 -" clip-path="url(#p60df48ef90)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfcc8f838ad)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pfcc8f838ad)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35571,7 +35571,7 @@ L 254.117647 467.915294 L 254.117647 449.28 L 230.672269 449.28 z -" clip-path="url(#p84dda8c28b)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> +" clip-path="url(#pac04eb6c5c)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> @@ -35656,12 +35656,12 @@ L 252.242556 458.544207 L 252.512354 458.533612 L 252.782151 458.527365 L 253.051948 458.525316 -" clip-path="url(#p84dda8c28b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pac04eb6c5c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pac04eb6c5c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35679,7 +35679,7 @@ L 282.252101 467.915294 L 282.252101 449.28 L 258.806723 449.28 z -" clip-path="url(#pcfa3a8427c)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> +" clip-path="url(#p6bb64efd46)" style="fill: #b1b1ff; opacity: 0.5; stroke: #b1b1ff; stroke-linejoin: miter"/> @@ -35764,12 +35764,12 @@ L 280.37701 458.540776 L 280.646807 458.532106 L 280.916605 458.526993 L 281.186402 458.525316 -" clip-path="url(#pcfa3a8427c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6bb64efd46)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6bb64efd46)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35787,7 +35787,7 @@ L 310.386555 467.915294 L 310.386555 449.28 L 286.941176 449.28 z -" clip-path="url(#p55cb3e1f27)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> +" clip-path="url(#p6d23ee7a8e)" style="fill: #a5a5ff; opacity: 0.5; stroke: #a5a5ff; stroke-linejoin: miter"/> @@ -35872,12 +35872,12 @@ L 308.511464 458.543034 L 308.781261 458.533098 L 309.051058 458.527238 L 309.320856 458.525316 -" clip-path="url(#p55cb3e1f27)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6d23ee7a8e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6d23ee7a8e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -35895,7 +35895,7 @@ L 338.521008 467.915294 L 338.521008 449.28 L 315.07563 449.28 z -" clip-path="url(#pbaae2a8522)" style="fill: #7171ff; opacity: 0.5; stroke: #7171ff; stroke-linejoin: miter"/> +" clip-path="url(#paf31a20e64)" style="fill: #7171ff; opacity: 0.5; stroke: #7171ff; stroke-linejoin: miter"/> @@ -35980,12 +35980,12 @@ L 336.645918 458.551909 L 336.915715 458.536996 L 337.185512 458.5282 L 337.455309 458.525316 -" clip-path="url(#pbaae2a8522)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paf31a20e64)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#paf31a20e64)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36003,7 +36003,7 @@ L 366.655462 467.915294 L 366.655462 449.28 L 343.210084 449.28 z -" clip-path="url(#pd2d75695f6)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> +" clip-path="url(#pb2701edc11)" style="fill: #9999ff; opacity: 0.5; stroke: #9999ff; stroke-linejoin: miter"/> @@ -36088,12 +36088,12 @@ L 364.780372 458.545604 L 365.050169 458.534226 L 365.319966 458.527516 L 365.589763 458.525316 -" clip-path="url(#pd2d75695f6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb2701edc11)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pb2701edc11)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36111,7 +36111,7 @@ L 394.789916 467.915294 L 394.789916 449.28 L 371.344538 449.28 z -" clip-path="url(#p56c03cde85)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> +" clip-path="url(#ped56975020)" style="fill: #a1a1ff; opacity: 0.5; stroke: #a1a1ff; stroke-linejoin: miter"/> @@ -36196,12 +36196,12 @@ L 392.914825 458.533235 L 393.184623 458.528794 L 393.45442 458.526175 L 393.724217 458.525316 -" clip-path="url(#p56c03cde85)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#ped56975020)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#ped56975020)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36219,7 +36219,7 @@ L 422.92437 467.915294 L 422.92437 449.28 L 399.478992 449.28 z -" clip-path="url(#p3f7bed994f)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> +" clip-path="url(#p10ce64506c)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> @@ -36304,12 +36304,12 @@ L 421.049279 458.530407 L 421.319076 458.527552 L 421.588874 458.525868 L 421.858671 458.525316 -" clip-path="url(#p3f7bed994f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10ce64506c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p10ce64506c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36327,7 +36327,7 @@ L 451.058824 467.915294 L 451.058824 449.28 L 427.613445 449.28 z -" clip-path="url(#p407d5355da)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> +" clip-path="url(#p718e71ba1d)" style="fill: #ffadad; opacity: 0.5; stroke: #ffadad; stroke-linejoin: miter"/> @@ -36412,12 +36412,12 @@ L 449.183733 458.516273 L 449.45353 458.521344 L 449.723327 458.524335 L 449.993125 458.525316 -" clip-path="url(#p407d5355da)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p718e71ba1d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p718e71ba1d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36435,7 +36435,7 @@ L 479.193277 467.915294 L 479.193277 449.28 L 455.747899 449.28 z -" clip-path="url(#pfa8eee058a)" style="fill: #ffeded; opacity: 0.5; stroke: #ffeded; stroke-linejoin: miter"/> +" clip-path="url(#p5a228b32da)" style="fill: #ffeded; opacity: 0.5; stroke: #ffeded; stroke-linejoin: miter"/> @@ -36520,12 +36520,12 @@ L 477.318187 458.520706 L 477.587984 458.523291 L 477.857781 458.524815 L 478.127578 458.525316 -" clip-path="url(#pfa8eee058a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5a228b32da)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5a228b32da)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36543,7 +36543,7 @@ L 507.327731 467.915294 L 507.327731 449.28 L 483.882353 449.28 z -" clip-path="url(#pab5b2207b3)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> +" clip-path="url(#p93f26f9489)" style="fill: #fdfdff; opacity: 0.5; stroke: #fdfdff; stroke-linejoin: miter"/> @@ -36628,12 +36628,12 @@ L 505.45264 458.515312 L 505.722438 458.520922 L 505.992235 458.52423 L 506.262032 458.525316 -" clip-path="url(#pab5b2207b3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p93f26f9489)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p93f26f9489)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36651,7 +36651,7 @@ L 535.462185 467.915294 L 535.462185 449.28 L 512.016807 449.28 z -" clip-path="url(#p3a1d07f080)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> +" clip-path="url(#p4a4ed1b30f)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> @@ -36736,12 +36736,12 @@ L 533.587094 458.534952 L 533.856891 458.529548 L 534.126689 458.526361 L 534.396486 458.525316 -" clip-path="url(#p3a1d07f080)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4a4ed1b30f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4a4ed1b30f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36759,7 +36759,7 @@ L 563.596639 467.915294 L 563.596639 449.28 L 540.151261 449.28 z -" clip-path="url(#pf7b7c8e2eb)" style="fill: #ffeded; opacity: 0.5; stroke: #ffeded; stroke-linejoin: miter"/> +" clip-path="url(#pa7b5b315c3)" style="fill: #ffeded; opacity: 0.5; stroke: #ffeded; stroke-linejoin: miter"/> @@ -36844,12 +36844,12 @@ L 561.721548 458.523184 L 561.991345 458.524379 L 562.261142 458.525084 L 562.53094 458.525316 -" clip-path="url(#pf7b7c8e2eb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa7b5b315c3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa7b5b315c3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36867,7 +36867,7 @@ L 591.731092 467.915294 L 591.731092 449.28 L 568.285714 449.28 z -" clip-path="url(#p7385683ca4)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p4b69c0c0ab)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -36952,12 +36952,12 @@ L 589.856002 458.500033 L 590.125799 458.514211 L 590.395596 458.522573 L 590.665393 458.525316 -" clip-path="url(#p7385683ca4)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4b69c0c0ab)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4b69c0c0ab)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -36975,7 +36975,7 @@ L 619.865546 467.915294 L 619.865546 449.28 L 596.420168 449.28 z -" clip-path="url(#p41ded0743a)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> +" clip-path="url(#pa13c59b163)" style="fill: #ff9191; opacity: 0.5; stroke: #ff9191; stroke-linejoin: miter"/> @@ -37060,12 +37060,12 @@ L 617.990456 458.508604 L 618.260253 458.517976 L 618.53005 458.523503 L 618.799847 458.525316 -" clip-path="url(#p41ded0743a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa13c59b163)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa13c59b163)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37083,7 +37083,7 @@ L 113.445378 490.277647 L 113.445378 471.642353 L 90 471.642353 z -" clip-path="url(#p5f3dc98fe8)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> +" clip-path="url(#p173bcb68fa)" style="fill: #9191ff; opacity: 0.5; stroke: #9191ff; stroke-linejoin: miter"/> @@ -37168,12 +37168,12 @@ L 111.570287 481.165739 L 111.840085 481.163532 L 112.109882 481.162231 L 112.379679 481.161804 -" clip-path="url(#p5f3dc98fe8)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p173bcb68fa)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p173bcb68fa)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37191,7 +37191,7 @@ L 141.579832 490.277647 L 141.579832 471.642353 L 118.134454 471.642353 z -" clip-path="url(#p1fbe971d18)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> +" clip-path="url(#p778a25956e)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> @@ -37276,12 +37276,12 @@ L 139.704741 481.164234 L 139.974538 481.162871 L 140.244336 481.162068 L 140.514133 481.161804 -" clip-path="url(#p1fbe971d18)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p778a25956e)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p778a25956e)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37299,7 +37299,7 @@ L 169.714286 490.277647 L 169.714286 471.642353 L 146.268908 471.642353 z -" clip-path="url(#pa906890f7c)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> +" clip-path="url(#p6abd0692fd)" style="fill: #e5e5ff; opacity: 0.5; stroke: #e5e5ff; stroke-linejoin: miter"/> @@ -37384,12 +37384,12 @@ L 167.839195 481.165936 L 168.108992 481.163619 L 168.378789 481.162252 L 168.648587 481.161804 -" clip-path="url(#pa906890f7c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6abd0692fd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p6abd0692fd)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37407,7 +37407,7 @@ L 197.848739 490.277647 L 197.848739 471.642353 L 174.403361 471.642353 z -" clip-path="url(#p31b2cf25dd)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> +" clip-path="url(#p8a53afa90a)" style="fill: #f5f5ff; opacity: 0.5; stroke: #f5f5ff; stroke-linejoin: miter"/> @@ -37492,12 +37492,12 @@ L 195.973649 481.1597 L 196.243446 481.16088 L 196.513243 481.161576 L 196.78304 481.161804 -" clip-path="url(#p31b2cf25dd)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8a53afa90a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8a53afa90a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37515,7 +37515,7 @@ L 225.983193 490.277647 L 225.983193 471.642353 L 202.537815 471.642353 z -" clip-path="url(#p9d61a3ea6d)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> +" clip-path="url(#pe288434f89)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> @@ -37600,12 +37600,12 @@ L 224.108103 481.172929 L 224.3779 481.16669 L 224.647697 481.163011 L 224.917494 481.161804 -" clip-path="url(#p9d61a3ea6d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe288434f89)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pe288434f89)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37623,7 +37623,7 @@ L 254.117647 490.277647 L 254.117647 471.642353 L 230.672269 471.642353 z -" clip-path="url(#pb908068de3)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> +" clip-path="url(#p8c76e20148)" style="fill: #bdbdff; opacity: 0.5; stroke: #bdbdff; stroke-linejoin: miter"/> @@ -37708,12 +37708,12 @@ L 252.242556 481.170119 L 252.512354 481.165456 L 252.782151 481.162706 L 253.051948 481.161804 -" clip-path="url(#pb908068de3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8c76e20148)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p8c76e20148)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37731,7 +37731,7 @@ L 282.252101 490.277647 L 282.252101 471.642353 L 258.806723 471.642353 z -" clip-path="url(#p94cb45794f)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> +" clip-path="url(#pa68f4cfd0b)" style="fill: #c1c1ff; opacity: 0.5; stroke: #c1c1ff; stroke-linejoin: miter"/> @@ -37816,12 +37816,12 @@ L 280.37701 481.173222 L 280.646807 481.166819 L 280.916605 481.163043 L 281.186402 481.161804 -" clip-path="url(#p94cb45794f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa68f4cfd0b)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pa68f4cfd0b)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37839,7 +37839,7 @@ L 310.386555 490.277647 L 310.386555 471.642353 L 286.941176 471.642353 z -" clip-path="url(#p1a1be426ca)" style="fill: #a9a9ff; opacity: 0.5; stroke: #a9a9ff; stroke-linejoin: miter"/> +" clip-path="url(#p1bf133106c)" style="fill: #a9a9ff; opacity: 0.5; stroke: #a9a9ff; stroke-linejoin: miter"/> @@ -37924,12 +37924,12 @@ L 308.511464 481.176262 L 308.781261 481.168154 L 309.051058 481.163373 L 309.320856 481.161804 -" clip-path="url(#p1a1be426ca)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1bf133106c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p1bf133106c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -37947,7 +37947,7 @@ L 338.521008 490.277647 L 338.521008 471.642353 L 315.07563 471.642353 z -" clip-path="url(#p9f9733bcea)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> +" clip-path="url(#pca30fd67d6)" style="fill: #8d8dff; opacity: 0.5; stroke: #8d8dff; stroke-linejoin: miter"/> @@ -38032,12 +38032,12 @@ L 336.645918 481.180929 L 336.915715 481.170204 L 337.185512 481.163879 L 337.455309 481.161804 -" clip-path="url(#p9f9733bcea)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pca30fd67d6)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pca30fd67d6)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38055,7 +38055,7 @@ L 366.655462 490.277647 L 366.655462 471.642353 L 343.210084 471.642353 z -" clip-path="url(#p2d10916a10)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> +" clip-path="url(#p7fe6ec860c)" style="fill: #9d9dff; opacity: 0.5; stroke: #9d9dff; stroke-linejoin: miter"/> @@ -38140,12 +38140,12 @@ L 364.780372 481.178016 L 365.050169 481.168924 L 365.319966 481.163563 L 365.589763 481.161804 -" clip-path="url(#p2d10916a10)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7fe6ec860c)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p7fe6ec860c)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38163,7 +38163,7 @@ L 394.789916 490.277647 L 394.789916 471.642353 L 371.344538 471.642353 z -" clip-path="url(#p9b39222a60)" style="fill: #5959ff; opacity: 0.5; stroke: #5959ff; stroke-linejoin: miter"/> +" clip-path="url(#p4263334766)" style="fill: #5959ff; opacity: 0.5; stroke: #5959ff; stroke-linejoin: miter"/> @@ -38248,12 +38248,12 @@ L 392.914825 481.18662 L 393.184623 481.172703 L 393.45442 481.164496 L 393.724217 481.161804 -" clip-path="url(#p9b39222a60)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4263334766)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p4263334766)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38271,7 +38271,7 @@ L 422.92437 490.277647 L 422.92437 471.642353 L 399.478992 471.642353 z -" clip-path="url(#p6e4fe96cb2)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> +" clip-path="url(#p5b8b25d5a2)" style="fill: #c5c5ff; opacity: 0.5; stroke: #c5c5ff; stroke-linejoin: miter"/> @@ -38356,12 +38356,12 @@ L 421.049279 481.167207 L 421.319076 481.164177 L 421.588874 481.16239 L 421.858671 481.161804 -" clip-path="url(#p6e4fe96cb2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5b8b25d5a2)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p5b8b25d5a2)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38379,7 +38379,7 @@ L 451.058824 490.277647 L 451.058824 471.642353 L 427.613445 471.642353 z -" clip-path="url(#p3e427179b5)" style="fill: #ff7575; opacity: 0.5; stroke: #ff7575; stroke-linejoin: miter"/> +" clip-path="url(#p46a0101f51)" style="fill: #ff7575; opacity: 0.5; stroke: #ff7575; stroke-linejoin: miter"/> @@ -38464,12 +38464,12 @@ L 449.183733 481.145069 L 449.45353 481.154454 L 449.723327 481.159989 L 449.993125 481.161804 -" clip-path="url(#p3e427179b5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p46a0101f51)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p46a0101f51)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38487,7 +38487,7 @@ L 479.193277 490.277647 L 479.193277 471.642353 L 455.747899 471.642353 z -" clip-path="url(#p0dba311d5a)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> +" clip-path="url(#pc562f6b96f)" style="fill: #e9e9ff; opacity: 0.5; stroke: #e9e9ff; stroke-linejoin: miter"/> @@ -38572,12 +38572,12 @@ L 477.318187 481.167085 L 477.587984 481.164123 L 477.857781 481.162377 L 478.127578 481.161804 -" clip-path="url(#p0dba311d5a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc562f6b96f)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc562f6b96f)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38595,7 +38595,7 @@ L 507.327731 490.277647 L 507.327731 471.642353 L 483.882353 471.642353 z -" clip-path="url(#p2617c1d1a5)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> +" clip-path="url(#pc3b5b0117d)" style="fill: #b9b9ff; opacity: 0.5; stroke: #b9b9ff; stroke-linejoin: miter"/> @@ -38680,12 +38680,12 @@ L 505.45264 481.174124 L 505.722438 481.167215 L 505.992235 481.163141 L 506.262032 481.161804 -" clip-path="url(#p2617c1d1a5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc3b5b0117d)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#pc3b5b0117d)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38703,7 +38703,7 @@ L 535.462185 490.277647 L 535.462185 471.642353 L 512.016807 471.642353 z -" clip-path="url(#p035801f782)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> +" clip-path="url(#p164889abf3)" style="fill: #ededff; opacity: 0.5; stroke: #ededff; stroke-linejoin: miter"/> @@ -38788,12 +38788,12 @@ L 533.587094 481.163328 L 533.856891 481.162473 L 534.126689 481.161969 L 534.396486 481.161804 -" clip-path="url(#p035801f782)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p164889abf3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p164889abf3)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38811,7 +38811,7 @@ L 563.596639 490.277647 L 563.596639 471.642353 L 540.151261 471.642353 z -" clip-path="url(#p89a08212c3)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> +" clip-path="url(#p72b758185a)" style="fill: #fff5f5; opacity: 0.5; stroke: #fff5f5; stroke-linejoin: miter"/> @@ -38896,12 +38896,12 @@ L 561.721548 481.152977 L 561.991345 481.157927 L 562.261142 481.160847 L 562.53094 481.161804 -" clip-path="url(#p89a08212c3)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p72b758185a)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p72b758185a)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -38919,7 +38919,7 @@ L 591.731092 490.277647 L 591.731092 471.642353 L 568.285714 471.642353 z -" clip-path="url(#p5a3eef6f55)" style="fill: #ff6969; opacity: 0.5; stroke: #ff6969; stroke-linejoin: miter"/> +" clip-path="url(#p37b071b444)" style="fill: #ff6969; opacity: 0.5; stroke: #ff6969; stroke-linejoin: miter"/> @@ -39004,12 +39004,12 @@ L 589.856002 481.149053 L 590.125799 481.156204 L 590.395596 481.160421 L 590.665393 481.161804 -" clip-path="url(#p5a3eef6f55)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p37b071b444)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p37b071b444)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -39027,7 +39027,7 @@ L 619.865546 490.277647 L 619.865546 471.642353 L 596.420168 471.642353 z -" clip-path="url(#p7f45f008a5)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> +" clip-path="url(#p41a5bd9e68)" style="fill: #ff5555; opacity: 0.5; stroke: #ff5555; stroke-linejoin: miter"/> @@ -39112,12 +39112,12 @@ L 617.990456 481.143418 L 618.260253 481.153729 L 618.53005 481.15981 L 618.799847 481.161804 -" clip-path="url(#p7f45f008a5)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p41a5bd9e68)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p41a5bd9e68)" style="fill: none; stroke: #000000; stroke-width: 0.5; stroke-linecap: square"/> @@ -39173,7 +39173,7 @@ z - - - + + @@ -39368,7 +39368,7 @@ z - - - + + @@ -39563,7 +39563,7 @@ z - - - + + @@ -39758,7 +39758,7 @@ z - - - + + @@ -39953,7 +39953,7 @@ z - - - + + @@ -40148,7 +40148,7 @@ z - - - + + @@ -40343,7 +40343,7 @@ z - - - + + @@ -40538,7 +40538,7 @@ z - - - + + @@ -40733,7 +40733,7 @@ z - - - + + @@ -40928,7 +40928,7 @@ z - - - + + @@ -41123,7 +41123,7 @@ z - - - + + @@ -41318,7 +41318,7 @@ z - - - + + @@ -41513,7 +41513,7 @@ z - - - + + @@ -41708,7 +41708,7 @@ z - - - + + @@ -41903,7 +41903,7 @@ z - - - + + @@ -42098,7 +42098,7 @@ z - - - + + @@ -42293,7 +42293,7 @@ z - - - + + @@ -42488,7 +42488,7 @@ z - - - + + @@ -42683,7 +42683,7 @@ z - - - + + @@ -42878,7 +42878,7 @@ z - - - + + @@ -43073,7 +43073,7 @@ z - - - + + @@ -43268,7 +43268,7 @@ z - - - + + @@ -43463,7 +43463,7 @@ z - - - + + @@ -43658,7 +43658,7 @@ z - - - + + @@ -43853,7 +43853,7 @@ z - - - + + @@ -44048,7 +44048,7 @@ z - - - + + @@ -44243,7 +44243,7 @@ z - - - + + @@ -44438,7 +44438,7 @@ z - - - + + @@ -44725,7 +44725,7 @@ z - - - + + @@ -44920,7 +44920,7 @@ z - - - + + @@ -45115,7 +45115,7 @@ z - - - + + @@ -45310,7 +45310,7 @@ z - - - + + @@ -45505,7 +45505,7 @@ z - - - + + @@ -45700,7 +45700,7 @@ z - - - + + @@ -45895,7 +45895,7 @@ z - - - + + @@ -46090,7 +46090,7 @@ z - - - + + @@ -46285,7 +46285,7 @@ z - - - + + @@ -46480,7 +46480,7 @@ z - - - + + @@ -46783,1090 +46783,1090 @@ z - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - 2024-11-21T17:26:20.009910 + image/svg+xml @@ -37,20 +37,20 @@ L 47.783588 53.206588 z " style="fill: #ffffff"/> - + +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" id="image910944a4ca" transform="scale(1 -1) translate(0 -219.6)" x="47.783588" y="-52.929412" width="219.6" height="219.6"/> - - + @@ -86,7 +86,7 @@ z - + @@ -125,7 +125,7 @@ z - + @@ -159,7 +159,7 @@ z - + @@ -204,7 +204,7 @@ z - + @@ -258,7 +258,7 @@ z - + @@ -290,12 +290,12 @@ z - - + @@ -308,7 +308,7 @@ L -3.5 0 - + @@ -321,7 +321,7 @@ L -3.5 0 - + @@ -334,7 +334,7 @@ L -3.5 0 - + @@ -347,7 +347,7 @@ L -3.5 0 - + @@ -360,7 +360,7 @@ L -3.5 0 - + @@ -632,15 +632,15 @@ L 332.183588 53.206588 z " style="fill: #ffffff"/> - + +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" id="imagee1b7aa8290" transform="scale(1 -1) translate(0 -219.6)" x="332.183588" y="-52.929412" width="219.6" height="219.6"/> - + @@ -653,7 +653,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -666,7 +666,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -679,7 +679,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -692,7 +692,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -705,7 +705,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -721,7 +721,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -734,7 +734,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -747,7 +747,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -760,7 +760,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -773,7 +773,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -786,7 +786,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAG5klEQVR4nO3dW26bZRSF4e34d+ycmlbp - + @@ -1019,15 +1019,15 @@ L 616.583588 53.206588 z " style="fill: #ffffff"/> - + +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" id="imageb3f6dda0c8" transform="scale(1 -1) translate(0 -219.6)" x="616.583588" y="-52.929412" width="219.6" height="219.6"/> - + @@ -1040,7 +1040,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1053,7 +1053,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1066,7 +1066,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1079,7 +1079,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1092,7 +1092,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1108,7 +1108,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1121,7 +1121,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1134,7 +1134,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1147,7 +1147,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1160,7 +1160,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1173,7 +1173,7 @@ iVBORw0KGgoAAAANSUhEUgAAATEAAAExCAYAAAAUZZVoAAAHYElEQVR4nO3dz2odeBnG8eckJ2mTNG3T - + @@ -1335,13 +1335,13 @@ z - + - + - + diff --git a/docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg b/docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg index b5208833..a046a608 100644 --- a/docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg +++ b/docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:26:35.023278 + image/svg+xml @@ -37,20 +37,20 @@ L 36.72 34.56 z " style="fill: #ffffff"/> - + +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" id="image14b2b40692" transform="scale(1 -1) translate(0 -221.76)" x="36.72" y="-34.56" width="221.76" height="221.76"/> - - + @@ -86,7 +86,7 @@ z - + @@ -116,7 +116,7 @@ z - + @@ -156,7 +156,7 @@ z - + @@ -204,7 +204,7 @@ z - + @@ -239,7 +239,7 @@ z - + @@ -282,12 +282,12 @@ z - - + @@ -300,7 +300,7 @@ L -3.5 0 - + @@ -314,7 +314,7 @@ L -3.5 0 - + @@ -328,7 +328,7 @@ L -3.5 0 - + @@ -342,7 +342,7 @@ L -3.5 0 - + @@ -356,7 +356,7 @@ L -3.5 0 - + @@ -381,7 +381,7 @@ L 258.48 256.32 - + From 6129f1a51bd8a102d6663309c04104fbb042ae64 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 17:44:53 -0500 Subject: [PATCH 074/107] cleared date --- .../tutorials/plot_05_place_cells.svg | 458 +++++++++--------- .../tutorials/plot_06_calcium_imaging.svg | 46 +- 2 files changed, 252 insertions(+), 252 deletions(-) diff --git a/docs/assets/thumbnails/tutorials/plot_05_place_cells.svg b/docs/assets/thumbnails/tutorials/plot_05_place_cells.svg index 129e2251..18aff11a 100644 --- a/docs/assets/thumbnails/tutorials/plot_05_place_cells.svg +++ b/docs/assets/thumbnails/tutorials/plot_05_place_cells.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:26:49.366255 + image/svg+xml @@ -141,7 +141,7 @@ L 163.282375 89.992092 L 150.859369 90.452067 L 138.436364 86.592956 z -" clip-path="url(#p2a1ea0cd24)" style="fill: #1f77b4"/> +" clip-path="url(#p869cbe3da6)" style="fill: #1f77b4"/> @@ -269,7 +269,7 @@ L 163.282375 95.546095 L 150.859369 95.546095 L 138.436364 91.686983 z -" clip-path="url(#pb65756ce19)" style="fill: #1f77b4"/> +" clip-path="url(#pb60de23a06)" style="fill: #1f77b4"/> @@ -397,7 +397,7 @@ L 163.282375 98.516288 L 150.859369 97.387854 L 138.436364 96.781011 z -" clip-path="url(#pc84646f90c)" style="fill: #1f77b4"/> +" clip-path="url(#pf421811ab5)" style="fill: #1f77b4"/> @@ -525,7 +525,7 @@ L 163.282375 105.128713 L 150.859369 103.78146 L 138.436364 101.875038 z -" clip-path="url(#p57b85ad532)" style="fill: #1f77b4"/> +" clip-path="url(#pcbc2f09ff8)" style="fill: #1f77b4"/> @@ -653,7 +653,7 @@ L 163.282375 109.944734 L 150.859369 108.163866 L 138.436364 106.969066 z -" clip-path="url(#p70f5f4ec01)" style="fill: #1f77b4"/> +" clip-path="url(#p2dc4942c20)" style="fill: #1f77b4"/> @@ -781,7 +781,7 @@ L 163.282375 112.873397 L 150.859369 112.335632 L 138.436364 112.063093 z -" clip-path="url(#pa5fce1bda9)" style="fill: #1f77b4"/> +" clip-path="url(#p30dbbc4791)" style="fill: #1f77b4"/> @@ -909,7 +909,7 @@ L 163.282375 119.118836 L 150.859369 117.422188 L 138.436364 117.157121 z -" clip-path="url(#pf4593df426)" style="fill: #1f77b4"/> +" clip-path="url(#p8d981f7da9)" style="fill: #1f77b4"/> @@ -1037,7 +1037,7 @@ L 163.282375 124.866066 L 150.859369 123.148398 L 138.436364 122.251149 z -" clip-path="url(#p106130fc18)" style="fill: #1f77b4"/> +" clip-path="url(#p33a77c244c)" style="fill: #1f77b4"/> @@ -1165,7 +1165,7 @@ L 163.282375 130.031018 L 150.859369 128.568937 L 138.436364 127.345176 z -" clip-path="url(#pc950e56111)" style="fill: #1f77b4"/> +" clip-path="url(#p0e1f94e832)" style="fill: #1f77b4"/> @@ -1293,7 +1293,7 @@ L 163.282375 134.247076 L 150.859369 133.904036 L 138.436364 132.439204 z -" clip-path="url(#p50b0c8bf60)" style="fill: #1f77b4"/> +" clip-path="url(#p1bbdbfa610)" style="fill: #1f77b4"/> @@ -1421,7 +1421,7 @@ L 163.282375 138.321252 L 150.859369 137.533231 L 138.436364 138.872534 z -" clip-path="url(#pf0aafcc34f)" style="fill: #1f77b4"/> +" clip-path="url(#p97e2361524)" style="fill: #1f77b4"/> @@ -1549,7 +1549,7 @@ L 163.282375 143.018307 L 150.859369 142.627259 L 138.436364 143.441972 z -" clip-path="url(#p98a91c8a49)" style="fill: #1f77b4"/> +" clip-path="url(#p9602cf6bf9)" style="fill: #1f77b4"/> @@ -1677,7 +1677,7 @@ L 163.282375 147.721286 L 150.859369 149.890333 L 138.436364 150.910121 z -" clip-path="url(#pb09f3886f3)" style="fill: #1f77b4"/> +" clip-path="url(#pdeb2ac2882)" style="fill: #1f77b4"/> @@ -1805,7 +1805,7 @@ L 163.282375 152.815314 L 150.859369 154.134299 L 138.436364 155.833457 z -" clip-path="url(#p6d1020c618)" style="fill: #1f77b4"/> +" clip-path="url(#p12efed3626)" style="fill: #1f77b4"/> @@ -1933,7 +1933,7 @@ L 163.282375 157.909342 L 150.859369 160.154496 L 138.436364 161.474114 z -" clip-path="url(#p8b9b9b6f0a)" style="fill: #1f77b4"/> +" clip-path="url(#p9829bb293e)" style="fill: #1f77b4"/> @@ -2061,7 +2061,7 @@ L 163.282375 163.003369 L 150.859369 164.886826 L 138.436364 165.554307 z -" clip-path="url(#pc985119a00)" style="fill: #1f77b4"/> +" clip-path="url(#p8271a40ae2)" style="fill: #1f77b4"/> @@ -2189,7 +2189,7 @@ L 163.282375 168.097397 L 150.859369 169.511636 L 138.436364 171.404623 z -" clip-path="url(#pc274d882b6)" style="fill: #1f77b4"/> +" clip-path="url(#p1d2328fedf)" style="fill: #1f77b4"/> @@ -2317,7 +2317,7 @@ L 163.282375 174.434254 L 150.859369 173.77534 L 138.436364 174.716213 z -" clip-path="url(#p85bfd8ab4a)" style="fill: #1f77b4"/> +" clip-path="url(#p05b416a49c)" style="fill: #1f77b4"/> @@ -2445,7 +2445,7 @@ L 163.282375 179.441196 L 150.859369 178.610596 L 138.436364 180.43751 z -" clip-path="url(#pfab650f10b)" style="fill: #1f77b4"/> +" clip-path="url(#p23a490e583)" style="fill: #1f77b4"/> @@ -2573,7 +2573,7 @@ L 163.282375 184.220139 L 150.859369 185.504664 L 138.436364 185.803448 z -" clip-path="url(#paeecc61426)" style="fill: #1f77b4"/> +" clip-path="url(#p06bc321118)" style="fill: #1f77b4"/> @@ -2701,7 +2701,7 @@ L 163.282375 189.151042 L 150.859369 189.321551 L 138.436364 189.774823 z -" clip-path="url(#p9109397137)" style="fill: #1f77b4"/> +" clip-path="url(#p074c3409e6)" style="fill: #1f77b4"/> @@ -2829,7 +2829,7 @@ L 163.282375 193.999387 L 150.859369 193.917508 L 138.436364 195.393527 z -" clip-path="url(#pc8faa3b1c4)" style="fill: #1f77b4"/> +" clip-path="url(#p5f54fb0a26)" style="fill: #1f77b4"/> @@ -2957,7 +2957,7 @@ L 163.282375 199.083864 L 150.859369 199.861339 L 138.436364 201.34009 z -" clip-path="url(#p9d8a755184)" style="fill: #1f77b4"/> +" clip-path="url(#p7904aaaabf)" style="fill: #1f77b4"/> @@ -3085,7 +3085,7 @@ L 163.282375 204.409595 L 150.859369 204.626847 L 138.436364 205.752847 z -" clip-path="url(#paadc903ea8)" style="fill: #1f77b4"/> +" clip-path="url(#p67b8d51b39)" style="fill: #1f77b4"/> @@ -3213,7 +3213,7 @@ L 163.282375 211.436043 L 150.859369 211.457761 L 138.436364 211.187977 z -" clip-path="url(#p56673c467c)" style="fill: #1f77b4"/> +" clip-path="url(#pcaf51d1c2e)" style="fill: #1f77b4"/> @@ -3341,7 +3341,7 @@ L 163.282375 216.648408 L 150.859369 216.35221 L 138.436364 217.0824 z -" clip-path="url(#p9c5d09e342)" style="fill: #1f77b4"/> +" clip-path="url(#p64cb2cbb50)" style="fill: #1f77b4"/> @@ -3469,7 +3469,7 @@ L 163.282375 219.96929 L 150.859369 220.341077 L 138.436364 221.536938 z -" clip-path="url(#pf050b10dd5)" style="fill: #1f77b4"/> +" clip-path="url(#p532ff29a68)" style="fill: #1f77b4"/> @@ -3597,7 +3597,7 @@ L 163.282375 226.523396 L 150.859369 226.543693 L 138.436364 226.930503 z -" clip-path="url(#p3defb47ea2)" style="fill: #1f77b4"/> +" clip-path="url(#p75fe654b26)" style="fill: #1f77b4"/> @@ -3725,7 +3725,7 @@ L 163.282375 231.091986 L 150.859369 230.330212 L 138.436364 232.134856 z -" clip-path="url(#p06f6176b03)" style="fill: #1f77b4"/> +" clip-path="url(#pab51c79ed3)" style="fill: #1f77b4"/> @@ -3853,7 +3853,7 @@ L 163.282375 236.953139 L 150.859369 237.117517 L 138.436364 237.372938 z -" clip-path="url(#p5592a74c04)" style="fill: #1f77b4"/> +" clip-path="url(#paf331cdef2)" style="fill: #1f77b4"/> @@ -3981,7 +3981,7 @@ L 163.282375 242.633186 L 150.859369 242.314969 L 138.436364 242.84597 z -" clip-path="url(#p41ae79cc8d)" style="fill: #1f77b4"/> +" clip-path="url(#p3b297f142c)" style="fill: #1f77b4"/> @@ -4109,7 +4109,7 @@ L 163.282375 248.182006 L 150.859369 247.514921 L 138.436364 246.392398 z -" clip-path="url(#p4259896e41)" style="fill: #1f77b4"/> +" clip-path="url(#p56b7fbeaef)" style="fill: #1f77b4"/> @@ -4237,7 +4237,7 @@ L 163.282375 252.788528 L 150.859369 252.345603 L 138.436364 253.460949 z -" clip-path="url(#p20ed02ef01)" style="fill: #1f77b4"/> +" clip-path="url(#p0ef36148c4)" style="fill: #1f77b4"/> @@ -4365,7 +4365,7 @@ L 163.282375 258.2069 L 150.859369 258.378563 L 138.436364 258.342591 z -" clip-path="url(#p44df880763)" style="fill: #1f77b4"/> +" clip-path="url(#pfbfda0a00c)" style="fill: #1f77b4"/> @@ -4493,7 +4493,7 @@ L 163.282375 261.873813 L 150.859369 262.194923 L 138.436364 262.926893 z -" clip-path="url(#p49d739a855)" style="fill: #1f77b4"/> +" clip-path="url(#pe4e3c604b4)" style="fill: #1f77b4"/> @@ -4621,7 +4621,7 @@ L 163.282375 268.436002 L 150.859369 268.640149 L 138.436364 268.668522 z -" clip-path="url(#p91c102067c)" style="fill: #1f77b4"/> +" clip-path="url(#p816c8a6388)" style="fill: #1f77b4"/> @@ -4749,7 +4749,7 @@ L 163.282375 272.736498 L 150.859369 273.112653 L 138.436364 273.177522 z -" clip-path="url(#p568845cbc6)" style="fill: #1f77b4"/> +" clip-path="url(#pa5e6635d22)" style="fill: #1f77b4"/> @@ -4877,7 +4877,7 @@ L 163.282375 278.50536 L 150.859369 278.27724 L 138.436364 278.60638 z -" clip-path="url(#pfe369ca5c6)" style="fill: #1f77b4"/> +" clip-path="url(#p7392a802cd)" style="fill: #1f77b4"/> @@ -5005,7 +5005,7 @@ L 163.282375 280.96861 L 150.859369 280.997298 L 138.436364 282.101848 z -" clip-path="url(#p91f62c74fd)" style="fill: #1f77b4"/> +" clip-path="url(#pd848ec7eb9)" style="fill: #1f77b4"/> @@ -5133,7 +5133,7 @@ L 163.282375 288.899983 L 150.859369 289.119142 L 138.436364 289.119142 z -" clip-path="url(#pd246a78a7e)" style="fill: #1f77b4"/> +" clip-path="url(#p61ddeb33c7)" style="fill: #1f77b4"/> @@ -5261,7 +5261,7 @@ L 163.282375 291.583257 L 150.859369 293.001435 L 138.436364 293.711703 z -" clip-path="url(#pcd250c6099)" style="fill: #1f77b4"/> +" clip-path="url(#p457ab5f791)" style="fill: #1f77b4"/> @@ -5389,7 +5389,7 @@ L 163.282375 299.142828 L 150.859369 299.155731 L 138.436364 299.307198 z -" clip-path="url(#p28a991e51a)" style="fill: #1f77b4"/> +" clip-path="url(#p1c775d4b82)" style="fill: #1f77b4"/> @@ -5517,7 +5517,7 @@ L 163.282375 303.68113 L 150.859369 304.055015 L 138.436364 304.257949 z -" clip-path="url(#pbaf40ecbb6)" style="fill: #1f77b4"/> +" clip-path="url(#pb2d341873e)" style="fill: #1f77b4"/> @@ -5645,7 +5645,7 @@ L 163.282375 308.595546 L 150.859369 308.857498 L 138.436364 309.284109 z -" clip-path="url(#p085006927c)" style="fill: #1f77b4"/> +" clip-path="url(#p4d318ab5e4)" style="fill: #1f77b4"/> @@ -5773,7 +5773,7 @@ L 163.282375 314.556022 L 150.859369 314.558632 L 138.436364 314.58928 z -" clip-path="url(#p93d218b450)" style="fill: #1f77b4"/> +" clip-path="url(#p82bd43172d)" style="fill: #1f77b4"/> @@ -5901,7 +5901,7 @@ L 163.282375 319.683308 L 150.859369 319.611416 L 138.436364 319.445293 z -" clip-path="url(#pf3f8024fc5)" style="fill: #1f77b4"/> +" clip-path="url(#p6615e88e70)" style="fill: #1f77b4"/> @@ -6029,7 +6029,7 @@ L 163.282375 324.588668 L 150.859369 324.603478 L 138.436364 324.597462 z -" clip-path="url(#p50ddab2ee4)" style="fill: #1f77b4"/> +" clip-path="url(#p6b4693e5af)" style="fill: #1f77b4"/> @@ -6157,7 +6157,7 @@ L 163.282375 329.71414 L 150.859369 329.146956 L 138.436364 326.393802 z -" clip-path="url(#p818c8747cd)" style="fill: #1f77b4"/> +" clip-path="url(#p855cd955fe)" style="fill: #1f77b4"/> @@ -6285,7 +6285,7 @@ L 163.282375 334.521814 L 150.859369 334.515759 L 138.436364 334.62707 z -" clip-path="url(#p16be4d8e84)" style="fill: #1f77b4"/> +" clip-path="url(#p2fac13dfa5)" style="fill: #1f77b4"/> @@ -6413,7 +6413,7 @@ L 163.282375 340.059418 L 150.859369 339.532577 L 138.436364 339.841389 z -" clip-path="url(#p3e9ba3754e)" style="fill: #1f77b4"/> +" clip-path="url(#p1bf92177ff)" style="fill: #1f77b4"/> @@ -6541,7 +6541,7 @@ L 163.282375 344.702088 L 150.859369 344.848432 L 138.436364 344.946892 z -" clip-path="url(#pfca057b264)" style="fill: #1f77b4"/> +" clip-path="url(#p9c31d06d42)" style="fill: #1f77b4"/> @@ -6669,7 +6669,7 @@ L 163.282375 349.763893 L 150.859369 350.056493 L 138.436364 349.799605 z -" clip-path="url(#p53c4a3e10e)" style="fill: #1f77b4"/> +" clip-path="url(#pe2019cb27d)" style="fill: #1f77b4"/> @@ -6797,7 +6797,7 @@ L 163.282375 355.224923 L 150.859369 355.09084 L 138.436364 355.015479 z -" clip-path="url(#p45e8e170f9)" style="fill: #1f77b4"/> +" clip-path="url(#p11002b5e43)" style="fill: #1f77b4"/> @@ -6925,7 +6925,7 @@ L 163.282375 359.542475 L 150.859369 358.925051 L 138.436364 359.01289 z -" clip-path="url(#p255b026332)" style="fill: #1f77b4"/> +" clip-path="url(#p2cc553a168)" style="fill: #1f77b4"/> @@ -7053,7 +7053,7 @@ L 163.282375 365.529556 L 150.859369 363.079744 L 138.436364 362.488053 z -" clip-path="url(#p059ba131c3)" style="fill: #1f77b4"/> +" clip-path="url(#pa9c630f521)" style="fill: #1f77b4"/> @@ -7181,7 +7181,7 @@ L 163.282375 370.623583 L 150.859369 370.623583 L 138.436364 370.370125 z -" clip-path="url(#p4d6d4a7411)" style="fill: #1f77b4"/> +" clip-path="url(#p9846568947)" style="fill: #1f77b4"/> @@ -7309,7 +7309,7 @@ L 163.282375 375.488923 L 150.859369 375.19077 L 138.436364 375.281553 z -" clip-path="url(#p3ea6f48365)" style="fill: #1f77b4"/> +" clip-path="url(#p93611b5d4d)" style="fill: #1f77b4"/> @@ -7437,7 +7437,7 @@ L 163.282375 379.611026 L 150.859369 380.074061 L 138.436364 380.201158 z -" clip-path="url(#p6651c7d293)" style="fill: #1f77b4"/> +" clip-path="url(#p5cf699d7b2)" style="fill: #1f77b4"/> @@ -7565,7 +7565,7 @@ L 163.282375 385.864216 L 150.859369 385.86747 L 138.436364 385.874052 z -" clip-path="url(#pcea9fe8bd8)" style="fill: #1f77b4"/> +" clip-path="url(#pa2e1fe56ff)" style="fill: #1f77b4"/> @@ -7693,7 +7693,7 @@ L 163.282375 390.999694 L 150.859369 390.999694 L 138.436364 390.999694 z -" clip-path="url(#pd7ea449ad6)" style="fill: #1f77b4"/> +" clip-path="url(#pf67a396a17)" style="fill: #1f77b4"/> @@ -7821,7 +7821,7 @@ L 163.282375 396.093721 L 150.859369 396.093721 L 138.436364 396.093721 z -" clip-path="url(#p92e32fec67)" style="fill: #1f77b4"/> +" clip-path="url(#pc18ecd459c)" style="fill: #1f77b4"/> @@ -7949,7 +7949,7 @@ L 163.282375 399.81562 L 150.859369 399.92333 L 138.436364 397.786498 z -" clip-path="url(#p370e76f4e0)" style="fill: #1f77b4"/> +" clip-path="url(#p7c02d88ae4)" style="fill: #1f77b4"/> @@ -8077,7 +8077,7 @@ L 163.282375 406.039391 L 150.859369 406.159944 L 138.436364 406.214551 z -" clip-path="url(#p4e3fe443b8)" style="fill: #1f77b4"/> +" clip-path="url(#pda68bcc599)" style="fill: #1f77b4"/> @@ -8205,7 +8205,7 @@ L 163.282375 411.222154 L 150.859369 410.951038 L 138.436364 410.760554 z -" clip-path="url(#p95d5cb959a)" style="fill: #1f77b4"/> +" clip-path="url(#p7dbddc4050)" style="fill: #1f77b4"/> @@ -8333,7 +8333,7 @@ L 163.282375 416.469832 L 150.859369 416.469832 L 138.436364 416.469832 z -" clip-path="url(#p1fb40a88f2)" style="fill: #1f77b4"/> +" clip-path="url(#p47b44aa154)" style="fill: #1f77b4"/> @@ -8461,7 +8461,7 @@ L 163.282375 419.059984 L 150.859369 419.011074 L 138.436364 419.329063 z -" clip-path="url(#p51f897b34d)" style="fill: #1f77b4"/> +" clip-path="url(#p449f32317b)" style="fill: #1f77b4"/> @@ -8589,7 +8589,7 @@ L 163.282375 425.56209 L 150.859369 425.850064 L 138.436364 425.320643 z -" clip-path="url(#pe07b6450c9)" style="fill: #1f77b4"/> +" clip-path="url(#p077a9bd908)" style="fill: #1f77b4"/> @@ -8717,7 +8717,7 @@ L 163.282375 431.751914 L 150.859369 431.751914 L 138.436364 431.667973 z -" clip-path="url(#p24fa652038)" style="fill: #1f77b4"/> +" clip-path="url(#p1f9801d066)" style="fill: #1f77b4"/> @@ -8845,7 +8845,7 @@ L 163.282375 436.682896 L 150.859369 436.789599 L 138.436364 436.845942 z -" clip-path="url(#p07c5620f56)" style="fill: #1f77b4"/> +" clip-path="url(#p800e5ed42a)" style="fill: #1f77b4"/> @@ -8973,7 +8973,7 @@ L 163.282375 439.673099 L 150.859369 439.474353 L 138.436364 440.919594 z -" clip-path="url(#p4e3fafc268)" style="fill: #1f77b4"/> +" clip-path="url(#p9a3586bb8c)" style="fill: #1f77b4"/> @@ -9101,7 +9101,7 @@ L 163.282375 447.033997 L 150.859369 447.033997 L 138.436364 447.033997 z -" clip-path="url(#pb2b68905a4)" style="fill: #1f77b4"/> +" clip-path="url(#paa1417dae4)" style="fill: #1f77b4"/> @@ -9229,7 +9229,7 @@ L 163.282375 451.290097 L 150.859369 451.024951 L 138.436364 451.215028 z -" clip-path="url(#p5ccec6cc11)" style="fill: #1f77b4"/> +" clip-path="url(#p43105f0b26)" style="fill: #1f77b4"/> @@ -9357,7 +9357,7 @@ L 163.282375 455.093982 L 150.859369 453.986369 L 138.436364 455.030861 z -" clip-path="url(#p8bf73fadf1)" style="fill: #1f77b4"/> +" clip-path="url(#pc605266377)" style="fill: #1f77b4"/> @@ -9485,7 +9485,7 @@ L 163.282375 461.11904 L 150.859369 461.654235 L 138.436364 459.394492 z -" clip-path="url(#p4fcc7c3d31)" style="fill: #1f77b4"/> +" clip-path="url(#pc10817ad20)" style="fill: #1f77b4"/> @@ -9613,7 +9613,7 @@ L 163.282375 466.609699 L 150.859369 466.303741 L 138.436364 466.723316 z -" clip-path="url(#p0b0e55b4e7)" style="fill: #1f77b4"/> +" clip-path="url(#pb57414a88a)" style="fill: #1f77b4"/> @@ -9741,7 +9741,7 @@ L 163.282375 471.903828 L 150.859369 471.858754 L 138.436364 470.901622 z -" clip-path="url(#p024f6ce5bc)" style="fill: #1f77b4"/> +" clip-path="url(#p527d7012c9)" style="fill: #1f77b4"/> @@ -9869,7 +9869,7 @@ L 163.282375 477.140786 L 150.859369 476.755216 L 138.436364 477.249316 z -" clip-path="url(#pba928d6504)" style="fill: #1f77b4"/> +" clip-path="url(#pbfb45a39ff)" style="fill: #1f77b4"/> @@ -9997,7 +9997,7 @@ L 163.282375 482.311639 L 150.859369 482.69219 L 138.436364 482.305189 z -" clip-path="url(#p59948fa358)" style="fill: #1f77b4"/> +" clip-path="url(#pebb1e967f8)" style="fill: #1f77b4"/> @@ -10125,7 +10125,7 @@ L 163.282375 487.697601 L 150.859369 487.296255 L 138.436364 487.65104 z -" clip-path="url(#p2ec0e239ab)" style="fill: #1f77b4"/> +" clip-path="url(#peb2a94ce0d)" style="fill: #1f77b4"/> @@ -10253,7 +10253,7 @@ L 163.282375 492.500459 L 150.859369 492.394171 L 138.436364 492.815875 z -" clip-path="url(#p162b2678dc)" style="fill: #1f77b4"/> +" clip-path="url(#pbe021dbe48)" style="fill: #1f77b4"/> @@ -10381,7 +10381,7 @@ L 163.282375 497.088106 L 150.859369 497.565971 L 138.436364 497.298383 z -" clip-path="url(#pa01a4e67e1)" style="fill: #1f77b4"/> +" clip-path="url(#p4a34a42220)" style="fill: #1f77b4"/> @@ -10509,7 +10509,7 @@ L 163.282375 501.880392 L 150.859369 502.122913 L 138.436364 502.738834 z -" clip-path="url(#p2c5c8ab941)" style="fill: #1f77b4"/> +" clip-path="url(#pc96bc38627)" style="fill: #1f77b4"/> @@ -10637,7 +10637,7 @@ L 163.282375 508.162328 L 150.859369 507.760611 L 138.436364 506.832351 z -" clip-path="url(#p83f171293d)" style="fill: #1f77b4"/> +" clip-path="url(#p57abd05489)" style="fill: #1f77b4"/> @@ -10765,7 +10765,7 @@ L 163.282375 513.256355 L 150.859369 513.055497 L 138.436364 513.256355 z -" clip-path="url(#p79751c21e1)" style="fill: #1f77b4"/> +" clip-path="url(#p1c4c140e9e)" style="fill: #1f77b4"/> @@ -10893,7 +10893,7 @@ L 163.282375 517.962884 L 150.859369 518.171842 L 138.436364 518.12872 z -" clip-path="url(#p7d0dff19e1)" style="fill: #1f77b4"/> +" clip-path="url(#p822251d9d7)" style="fill: #1f77b4"/> @@ -11021,7 +11021,7 @@ L 163.282375 523.117458 L 150.859369 523.343981 L 138.436364 523.361287 z -" clip-path="url(#p057c37fd19)" style="fill: #1f77b4"/> +" clip-path="url(#p6f05b0998d)" style="fill: #1f77b4"/> @@ -11149,7 +11149,7 @@ L 163.282375 528.538438 L 150.859369 527.254263 L 138.436364 525.349765 z -" clip-path="url(#p60895656ae)" style="fill: #1f77b4"/> +" clip-path="url(#p4be15e4970)" style="fill: #1f77b4"/> @@ -11277,7 +11277,7 @@ L 163.282375 533.513634 L 150.859369 533.562782 L 138.436364 533.55831 z -" clip-path="url(#p1730b0f3fb)" style="fill: #1f77b4"/> +" clip-path="url(#pc162751a79)" style="fill: #1f77b4"/> @@ -11405,7 +11405,7 @@ L 163.282375 538.593772 L 150.859369 538.634766 L 138.436364 538.675879 z -" clip-path="url(#pf9274429ea)" style="fill: #1f77b4"/> +" clip-path="url(#pf77629a5e5)" style="fill: #1f77b4"/> @@ -11533,7 +11533,7 @@ L 163.282375 542.357274 L 150.859369 542.523997 L 138.436364 542.210854 z -" clip-path="url(#pee3bf41c52)" style="fill: #1f77b4"/> +" clip-path="url(#p09bc741446)" style="fill: #1f77b4"/> @@ -11661,7 +11661,7 @@ L 163.282375 548.801991 L 150.859369 548.914548 L 138.436364 548.914548 z -" clip-path="url(#pa3697e79ca)" style="fill: #1f77b4"/> +" clip-path="url(#p1ef4ce3dc6)" style="fill: #1f77b4"/> @@ -11789,7 +11789,7 @@ L 163.282375 553.751302 L 150.859369 553.652958 L 138.436364 553.861406 z -" clip-path="url(#pcca8ab1a26)" style="fill: #1f77b4"/> +" clip-path="url(#p4074d4a89f)" style="fill: #1f77b4"/> @@ -11917,7 +11917,7 @@ L 163.282375 558.920692 L 150.859369 559.102603 L 138.436364 559.102603 z -" clip-path="url(#p61ac720fce)" style="fill: #1f77b4"/> +" clip-path="url(#p9b0ada917d)" style="fill: #1f77b4"/> @@ -12045,7 +12045,7 @@ L 163.282375 563.446248 L 150.859369 563.966138 L 138.436364 564.005856 z -" clip-path="url(#pf084b22e1e)" style="fill: #1f77b4"/> +" clip-path="url(#p58fc975a2a)" style="fill: #1f77b4"/> @@ -12173,7 +12173,7 @@ L 163.282375 568.679235 L 150.859369 568.829672 L 138.436364 569.036291 z -" clip-path="url(#pf1dc8b5f08)" style="fill: #1f77b4"/> +" clip-path="url(#p21758e9669)" style="fill: #1f77b4"/> @@ -12301,7 +12301,7 @@ L 163.282375 572.717169 L 150.859369 571.772432 L 138.436364 571.077914 z -" clip-path="url(#p4422ae0908)" style="fill: #1f77b4"/> +" clip-path="url(#p6a983e9a6a)" style="fill: #1f77b4"/> @@ -12429,7 +12429,7 @@ L 163.282375 579.478714 L 150.859369 579.478714 L 138.436364 579.478714 z -" clip-path="url(#pd123402b60)" style="fill: #1f77b4"/> +" clip-path="url(#pbdd710c131)" style="fill: #1f77b4"/> @@ -12557,7 +12557,7 @@ L 163.282375 584.572741 L 150.859369 584.572741 L 138.436364 584.572741 z -" clip-path="url(#p53cef94cf7)" style="fill: #1f77b4"/> +" clip-path="url(#pae412b7e13)" style="fill: #1f77b4"/> @@ -12685,7 +12685,7 @@ L 163.282375 589.123635 L 150.859369 589.499936 L 138.436364 588.976344 z -" clip-path="url(#p9dcac5b70a)" style="fill: #1f77b4"/> +" clip-path="url(#p7bb415e4ea)" style="fill: #1f77b4"/> @@ -12813,7 +12813,7 @@ L 163.282375 593.97332 L 150.859369 593.644395 L 138.436364 594.229481 z -" clip-path="url(#p448bdf4fa7)" style="fill: #1f77b4"/> +" clip-path="url(#pcb5111f267)" style="fill: #1f77b4"/> @@ -12941,7 +12941,7 @@ L 163.282375 599.582236 L 150.859369 599.491993 L 138.436364 599.346609 z -" clip-path="url(#pa1fec78940)" style="fill: #1f77b4"/> +" clip-path="url(#p660cbba39c)" style="fill: #1f77b4"/> @@ -13069,7 +13069,7 @@ L 163.282375 604.736839 L 150.859369 604.948851 L 138.436364 604.948851 z -" clip-path="url(#p393569d514)" style="fill: #1f77b4"/> +" clip-path="url(#p3add200560)" style="fill: #1f77b4"/> @@ -13197,7 +13197,7 @@ L 163.282375 610.042879 L 150.859369 610.042879 L 138.436364 610.015928 z -" clip-path="url(#p21e8b5002f)" style="fill: #1f77b4"/> +" clip-path="url(#p07aa61f9e6)" style="fill: #1f77b4"/> @@ -13325,7 +13325,7 @@ L 163.282375 613.569142 L 150.859369 613.884836 L 138.436364 614.818039 z -" clip-path="url(#pca286fe48b)" style="fill: #1f77b4"/> +" clip-path="url(#p286e3b2d5e)" style="fill: #1f77b4"/> @@ -13453,7 +13453,7 @@ L 163.282375 619.673507 L 150.859369 617.919418 L 138.436364 618.105152 z -" clip-path="url(#pddf26d57de)" style="fill: #1f77b4"/> +" clip-path="url(#pdb0715ac8f)" style="fill: #1f77b4"/> @@ -13581,7 +13581,7 @@ L 163.282375 625.243387 L 150.859369 625.24979 L 138.436364 625.044981 z -" clip-path="url(#p5d181d8e8b)" style="fill: #1f77b4"/> +" clip-path="url(#p474a296f50)" style="fill: #1f77b4"/> @@ -13709,7 +13709,7 @@ L 163.282375 630.418989 L 150.859369 630.418989 L 138.436364 630.418989 z -" clip-path="url(#pdf799b9b4e)" style="fill: #1f77b4"/> +" clip-path="url(#pdb88316892)" style="fill: #1f77b4"/> @@ -13837,7 +13837,7 @@ L 163.282375 635.513017 L 150.859369 635.384599 L 138.436364 635.513017 z -" clip-path="url(#pec18780e6a)" style="fill: #1f77b4"/> +" clip-path="url(#p57e4d07eb8)" style="fill: #1f77b4"/> @@ -13965,18 +13965,18 @@ L 163.282375 639.998942 L 150.859369 639.486309 L 138.436364 638.635865 z -" clip-path="url(#p7504786eb1)" style="fill: #1f77b4"/> +" clip-path="url(#p35dcbe485a)" style="fill: #1f77b4"/> - - + @@ -14012,7 +14012,7 @@ z - + @@ -14052,7 +14052,7 @@ z - + @@ -14087,7 +14087,7 @@ z - + @@ -14133,7 +14133,7 @@ z - + @@ -14188,7 +14188,7 @@ z - + @@ -14219,7 +14219,7 @@ z - + @@ -14234,7 +14234,7 @@ z - + @@ -14249,7 +14249,7 @@ z - + @@ -14500,331 +14500,331 @@ L 777.6 640.8 - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg b/docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg index 4d816a86..dbdff075 100644 --- a/docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg +++ b/docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg @@ -6,7 +6,7 @@ - 2024-11-21T17:27:10.094376 + image/svg+xml @@ -41,12 +41,12 @@ z - - + @@ -82,7 +82,7 @@ z - + @@ -111,7 +111,7 @@ z - + @@ -150,7 +150,7 @@ z - + @@ -197,7 +197,7 @@ z - + @@ -231,7 +231,7 @@ z - + @@ -271,7 +271,7 @@ z - + @@ -590,12 +590,12 @@ z - - + @@ -619,7 +619,7 @@ z - + @@ -634,7 +634,7 @@ z - + @@ -649,7 +649,7 @@ z - + @@ -664,7 +664,7 @@ z - + @@ -679,7 +679,7 @@ z - + @@ -694,7 +694,7 @@ z - + @@ -709,7 +709,7 @@ z - + @@ -736,7 +736,7 @@ z - + @@ -1003,7 +1003,7 @@ L 390.302704 275.526196 L 393.030894 278.943558 L 395.759083 277.90626 L 398.487273 270.043746 -" clip-path="url(#p1a3437ee01)" style="fill: none; stroke: #ff0000; stroke-width: 2; stroke-linecap: square"/> +" clip-path="url(#p3282574f43)" style="fill: none; stroke: #ff0000; stroke-width: 2; stroke-linecap: square"/> +" clip-path="url(#p3282574f43)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#p3282574f43)" style="fill: none; stroke: #008000; stroke-opacity: 0.5; stroke-width: 1.5; stroke-linecap: square"/> + From 2fa7d722df6b119fd87dfe5fbd7440811971299a Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 17:46:54 -0500 Subject: [PATCH 075/107] removed svgs --- .../background/plot_00_conceptual_intro.svg | 415 - .../background/plot_01_1D_basis_function.svg | 1294 - .../background/plot_02_ND_basis_function.svg | 8618 --- .../background/plot_03_1D_convolution.svg | 2840 - .../how_to_guide/plot_02_glm_demo.svg | 1853 - .../how_to_guide/plot_03_population_glm.svg | 1324 - .../how_to_guide/plot_04_batch_glm.svg | 1298 - .../plot_05_sklearn_pipeline_cv_demo.svg | 2006 - .../how_to_guide/plot_06_glm_pytree.svg | 3634 -- .../tutorials/plot_01_current_injection.svg | 5326 -- .../tutorials/plot_02_head_direction.svg | 49314 ---------------- .../tutorials/plot_03_grid_cells.svg | 1348 - .../thumbnails/tutorials/plot_04_v1_cells.svg | 388 - .../tutorials/plot_05_place_cells.svg | 14831 ----- .../tutorials/plot_06_calcium_imaging.svg | 1430 - 15 files changed, 95919 deletions(-) delete mode 100644 docs/assets/thumbnails/background/plot_00_conceptual_intro.svg delete mode 100644 docs/assets/thumbnails/background/plot_01_1D_basis_function.svg delete mode 100644 docs/assets/thumbnails/background/plot_02_ND_basis_function.svg delete mode 100644 docs/assets/thumbnails/background/plot_03_1D_convolution.svg delete mode 100644 docs/assets/thumbnails/how_to_guide/plot_02_glm_demo.svg delete mode 100644 docs/assets/thumbnails/how_to_guide/plot_03_population_glm.svg delete mode 100644 docs/assets/thumbnails/how_to_guide/plot_04_batch_glm.svg delete mode 100644 docs/assets/thumbnails/how_to_guide/plot_05_sklearn_pipeline_cv_demo.svg delete mode 100644 docs/assets/thumbnails/how_to_guide/plot_06_glm_pytree.svg delete mode 100644 docs/assets/thumbnails/tutorials/plot_01_current_injection.svg delete mode 100644 docs/assets/thumbnails/tutorials/plot_02_head_direction.svg delete mode 100644 docs/assets/thumbnails/tutorials/plot_03_grid_cells.svg delete mode 100644 docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg delete mode 100644 docs/assets/thumbnails/tutorials/plot_05_place_cells.svg delete mode 100644 docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg diff --git a/docs/assets/thumbnails/background/plot_00_conceptual_intro.svg b/docs/assets/thumbnails/background/plot_00_conceptual_intro.svg deleted file mode 100644 index 6757f795..00000000 --- a/docs/assets/thumbnails/background/plot_00_conceptual_intro.svg +++ /dev/null @@ -1,415 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - e - x - - Nonlinearity - Linear filter - - - - - - - Poisson - Spikes - Input - GLM model - - diff --git a/docs/assets/thumbnails/background/plot_01_1D_basis_function.svg b/docs/assets/thumbnails/background/plot_01_1D_basis_function.svg deleted file mode 100644 index fe983fea..00000000 --- a/docs/assets/thumbnails/background/plot_01_1D_basis_function.svg +++ /dev/null @@ -1,1294 +0,0 @@ - - - - - - - - - image/svg+xml - - - Matplotlib v3.9.2, https://matplotlib.org/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/assets/thumbnails/background/plot_02_ND_basis_function.svg b/docs/assets/thumbnails/background/plot_02_ND_basis_function.svg deleted file mode 100644 index cfddbc34..00000000 --- a/docs/assets/thumbnails/background/plot_02_ND_basis_function.svg +++ /dev/null @@ -1,8618 +0,0 @@ - - - - - - - - - image/svg+xml - - - Matplotlib v3.9.2, https://matplotlib.org/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/assets/thumbnails/background/plot_03_1D_convolution.svg b/docs/assets/thumbnails/background/plot_03_1D_convolution.svg deleted file mode 100644 index cde68ec9..00000000 --- a/docs/assets/thumbnails/background/plot_03_1D_convolution.svg +++ /dev/null @@ -1,2840 +0,0 @@ - - - - - - - - - image/svg+xml - - - Matplotlib v3.9.2, https://matplotlib.org/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/assets/thumbnails/how_to_guide/plot_02_glm_demo.svg b/docs/assets/thumbnails/how_to_guide/plot_02_glm_demo.svg deleted file mode 100644 index f0733a75..00000000 --- a/docs/assets/thumbnails/how_to_guide/plot_02_glm_demo.svg +++ /dev/null @@ -1,1853 +0,0 @@ - - - - - - - - - image/svg+xml - - - Matplotlib v3.9.2, https://matplotlib.org/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/assets/thumbnails/how_to_guide/plot_03_population_glm.svg b/docs/assets/thumbnails/how_to_guide/plot_03_population_glm.svg deleted file mode 100644 index 1f4e1ce0..00000000 --- a/docs/assets/thumbnails/how_to_guide/plot_03_population_glm.svg +++ /dev/null @@ -1,1324 +0,0 @@ - - - - - - - - - image/svg+xml - - - Matplotlib v3.9.2, https://matplotlib.org/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/assets/thumbnails/how_to_guide/plot_04_batch_glm.svg b/docs/assets/thumbnails/how_to_guide/plot_04_batch_glm.svg deleted file mode 100644 index 1dc2c74b..00000000 --- a/docs/assets/thumbnails/how_to_guide/plot_04_batch_glm.svg +++ /dev/null @@ -1,1298 +0,0 @@ - - - - - - - - - image/svg+xml - - - Matplotlib v3.9.2, https://matplotlib.org/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/assets/thumbnails/how_to_guide/plot_05_sklearn_pipeline_cv_demo.svg b/docs/assets/thumbnails/how_to_guide/plot_05_sklearn_pipeline_cv_demo.svg deleted file mode 100644 index e7359826..00000000 --- a/docs/assets/thumbnails/how_to_guide/plot_05_sklearn_pipeline_cv_demo.svg +++ /dev/null @@ -1,2006 +0,0 @@ - - - - - - - - - image/svg+xml - - - Matplotlib v3.9.2, https://matplotlib.org/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/assets/thumbnails/how_to_guide/plot_06_glm_pytree.svg b/docs/assets/thumbnails/how_to_guide/plot_06_glm_pytree.svg deleted file mode 100644 index 3d6c2801..00000000 --- a/docs/assets/thumbnails/how_to_guide/plot_06_glm_pytree.svg +++ /dev/null @@ -1,3634 +0,0 @@ - - - - - - - - - image/svg+xml - - - Matplotlib v3.9.2, https://matplotlib.org/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/assets/thumbnails/tutorials/plot_01_current_injection.svg b/docs/assets/thumbnails/tutorials/plot_01_current_injection.svg deleted file mode 100644 index b81a30e3..00000000 --- a/docs/assets/thumbnails/tutorials/plot_01_current_injection.svg +++ /dev/null @@ -1,5326 +0,0 @@ - - - - - - - - - image/svg+xml - - - Matplotlib v3.9.2, https://matplotlib.org/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/assets/thumbnails/tutorials/plot_02_head_direction.svg b/docs/assets/thumbnails/tutorials/plot_02_head_direction.svg deleted file mode 100644 index 334d668a..00000000 --- a/docs/assets/thumbnails/tutorials/plot_02_head_direction.svg +++ /dev/null @@ -1,49314 +0,0 @@ - - - - - - - - - image/svg+xml - - - Matplotlib v3.9.2, https://matplotlib.org/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/assets/thumbnails/tutorials/plot_03_grid_cells.svg b/docs/assets/thumbnails/tutorials/plot_03_grid_cells.svg deleted file mode 100644 index 76f30d7d..00000000 --- a/docs/assets/thumbnails/tutorials/plot_03_grid_cells.svg +++ /dev/null @@ -1,1348 +0,0 @@ - - - - - - - - - image/svg+xml - - - Matplotlib v3.9.2, https://matplotlib.org/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg b/docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg deleted file mode 100644 index a046a608..00000000 --- a/docs/assets/thumbnails/tutorials/plot_04_v1_cells.svg +++ /dev/null @@ -1,388 +0,0 @@ - - - - - - - - - image/svg+xml - - - Matplotlib v3.9.2, https://matplotlib.org/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/assets/thumbnails/tutorials/plot_05_place_cells.svg b/docs/assets/thumbnails/tutorials/plot_05_place_cells.svg deleted file mode 100644 index 18aff11a..00000000 --- a/docs/assets/thumbnails/tutorials/plot_05_place_cells.svg +++ /dev/null @@ -1,14831 +0,0 @@ - - - - - - - - - image/svg+xml - - - Matplotlib v3.9.2, https://matplotlib.org/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg b/docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg deleted file mode 100644 index dbdff075..00000000 --- a/docs/assets/thumbnails/tutorials/plot_06_calcium_imaging.svg +++ /dev/null @@ -1,1430 +0,0 @@ - - - - - - - - - image/svg+xml - - - Matplotlib v3.9.2, https://matplotlib.org/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From c89bae94ebd5b3d25f183eafd621ac844d01b9d2 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 17:49:02 -0500 Subject: [PATCH 076/107] reinserted save --- .gitignore | 3 +++ docs/background/plot_01_1D_basis_function.md | 2 +- docs/background/plot_02_ND_basis_function.md | 2 +- docs/background/plot_03_1D_convolution.md | 2 +- docs/how_to_guide/plot_02_glm_demo.md | 2 +- docs/how_to_guide/plot_03_population_glm.md | 2 +- docs/how_to_guide/plot_04_batch_glm.md | 2 +- docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md | 2 +- docs/how_to_guide/plot_06_glm_pytree.md | 2 +- docs/tutorials/plot_01_current_injection.md | 2 +- docs/tutorials/plot_02_head_direction.md | 2 +- docs/tutorials/plot_03_grid_cells.md | 2 +- docs/tutorials/plot_04_v1_cells.md | 2 +- docs/tutorials/plot_05_place_cells.md | 2 +- docs/tutorials/plot_06_calcium_imaging.md | 2 +- 15 files changed, 17 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index f0d8fd49..858dc99b 100644 --- a/.gitignore +++ b/.gitignore @@ -153,3 +153,6 @@ docs/data/ # rst generated files docs/stubs +# ignore the auto-generated svgs +docs/assets/thumbnails:wq + diff --git a/docs/background/plot_01_1D_basis_function.md b/docs/background/plot_01_1D_basis_function.md index c108a5fb..05edebe4 100644 --- a/docs/background/plot_01_1D_basis_function.md +++ b/docs/background/plot_01_1D_basis_function.md @@ -97,7 +97,7 @@ from pathlib import Path path = Path("../assets/thumbnails/background") if path.exists(): - fig.savefig(path / "plot_01_1D_basis_function.svg", metadata={"Date":""}) + fig.savefig(path / "plot_01_1D_basis_function.svg") ``` ## Setting the basis support diff --git a/docs/background/plot_02_ND_basis_function.md b/docs/background/plot_02_ND_basis_function.md index f35d8ddb..84bbcdeb 100644 --- a/docs/background/plot_02_ND_basis_function.md +++ b/docs/background/plot_02_ND_basis_function.md @@ -301,7 +301,7 @@ from pathlib import Path path = Path("../assets/thumbnails/background") if path.exists(): - fig.savefig(path / "plot_02_ND_basis_function.svg", metadata={"Date":""}) + fig.savefig(path / "plot_02_ND_basis_function.svg") ``` :::{info} diff --git a/docs/background/plot_03_1D_convolution.md b/docs/background/plot_03_1D_convolution.md index 4092dfee..04faf528 100644 --- a/docs/background/plot_03_1D_convolution.md +++ b/docs/background/plot_03_1D_convolution.md @@ -172,7 +172,7 @@ from pathlib import Path path = Path("../assets/thumbnails/background") if path.exists(): - fig.savefig(path / "plot_03_1D_convolution.svg", metadata={"Date":""}) + fig.savefig(path / "plot_03_1D_convolution.svg") ``` ## Convolve using [`Basis.compute_features`](nemos.basis.Basis.compute_features) diff --git a/docs/how_to_guide/plot_02_glm_demo.md b/docs/how_to_guide/plot_02_glm_demo.md index 67084c88..bdad8fc1 100644 --- a/docs/how_to_guide/plot_02_glm_demo.md +++ b/docs/how_to_guide/plot_02_glm_demo.md @@ -442,7 +442,7 @@ from pathlib import Path path = Path("../assets/thumbnails/how_to_guide") if path.exists(): - fig.savefig(path / "plot_02_glm_demo.svg", metadata={"Date":""}) + fig.savefig(path / "plot_02_glm_demo.svg") ``` diff --git a/docs/how_to_guide/plot_03_population_glm.md b/docs/how_to_guide/plot_03_population_glm.md index a4fc9f23..1239fed8 100644 --- a/docs/how_to_guide/plot_03_population_glm.md +++ b/docs/how_to_guide/plot_03_population_glm.md @@ -223,7 +223,7 @@ from pathlib import Path path = Path("../assets/thumbnails/how_to_guide") if path.exists(): - fig.savefig(path / "plot_03_population_glm.svg", metadata={"Date":""}) + fig.savefig(path / "plot_03_population_glm.svg") ``` ## FeaturePytree diff --git a/docs/how_to_guide/plot_04_batch_glm.md b/docs/how_to_guide/plot_04_batch_glm.md index d2ecf872..63342acc 100644 --- a/docs/how_to_guide/plot_04_batch_glm.md +++ b/docs/how_to_guide/plot_04_batch_glm.md @@ -201,7 +201,7 @@ from pathlib import Path path = Path("../assets/thumbnails/how_to_guide") if path.exists(): - fig.savefig(path / "plot_04_batch_glm.svg", metadata={"Date":""}) + fig.savefig(path / "plot_04_batch_glm.svg") ``` We can see that the log-likelihood is increasing but did not reach plateau yet. diff --git a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md index 2b0004ca..170ab68b 100644 --- a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md +++ b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md @@ -424,7 +424,7 @@ from pathlib import Path path = Path("../assets/thumbnails/how_to_guide") if path.exists(): - fig.savefig(path / "plot_05_sklearn_pipeline_cv_demo.svg", metadata={"Date":""}) + fig.savefig(path / "plot_05_sklearn_pipeline_cv_demo.svg") ``` :rocket::rocket::rocket: **Success!** :rocket::rocket::rocket: diff --git a/docs/how_to_guide/plot_06_glm_pytree.md b/docs/how_to_guide/plot_06_glm_pytree.md index e2511bd9..58146377 100644 --- a/docs/how_to_guide/plot_06_glm_pytree.md +++ b/docs/how_to_guide/plot_06_glm_pytree.md @@ -254,7 +254,7 @@ from pathlib import Path path = Path("../assets/thumbnails/how_to_guide") if path.exists(): - fig.savefig(path / "plot_06_glm_pytree.svg", metadata={"Date":""}) + fig.savefig(path / "plot_06_glm_pytree.svg") ``` diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md index ff4281f1..6f82cbd9 100644 --- a/docs/tutorials/plot_01_current_injection.md +++ b/docs/tutorials/plot_01_current_injection.md @@ -627,7 +627,7 @@ from pathlib import Path path = Path("../assets/thumbnails/tutorials") if path.exists(): - fig.savefig(path / "plot_01_current_injection.svg", metadata={"Date":""}) + fig.savefig(path / "plot_01_current_injection.svg") ``` What do we see above? Note that the y-axes in the final row are different for diff --git a/docs/tutorials/plot_02_head_direction.md b/docs/tutorials/plot_02_head_direction.md index 43dd9262..b6918bde 100644 --- a/docs/tutorials/plot_02_head_direction.md +++ b/docs/tutorials/plot_02_head_direction.md @@ -708,5 +708,5 @@ from pathlib import Path path = Path("../assets/thumbnails/tutorials") if path.exists(): - fig.savefig(path / "plot_02_head_direction.svg", metadata={"Date":""}) + fig.savefig(path / "plot_02_head_direction.svg") ``` \ No newline at end of file diff --git a/docs/tutorials/plot_03_grid_cells.md b/docs/tutorials/plot_03_grid_cells.md index d7d5d6f8..55e9dfee 100644 --- a/docs/tutorials/plot_03_grid_cells.md +++ b/docs/tutorials/plot_03_grid_cells.md @@ -337,5 +337,5 @@ from pathlib import Path path = Path("../assets/thumbnails/tutorials") if path.exists(): - fig.savefig(path / "plot_03_grid_cells.svg", metadata={"Date":""}) + fig.savefig(path / "plot_03_grid_cells.svg") ``` \ No newline at end of file diff --git a/docs/tutorials/plot_04_v1_cells.md b/docs/tutorials/plot_04_v1_cells.md index 60985584..d413a4be 100644 --- a/docs/tutorials/plot_04_v1_cells.md +++ b/docs/tutorials/plot_04_v1_cells.md @@ -240,7 +240,7 @@ from pathlib import Path path = Path("../assets/thumbnails/tutorials") if path.exists(): - fig.savefig(path / "plot_04_v1_cells.svg", metadata={"Date":""}) + fig.savefig(path / "plot_04_v1_cells.svg") ``` This receptive field gives us the spatial part of the linear response: it diff --git a/docs/tutorials/plot_05_place_cells.md b/docs/tutorials/plot_05_place_cells.md index b12435e8..a8e80020 100644 --- a/docs/tutorials/plot_05_place_cells.md +++ b/docs/tutorials/plot_05_place_cells.md @@ -152,7 +152,7 @@ from pathlib import Path path = Path("../assets/thumbnails/tutorials") if path.exists(): - fig.savefig(path / "plot_05_place_cells.svg", metadata={"Date":""}) + fig.savefig(path / "plot_05_place_cells.svg") ``` ## Phase precession diff --git a/docs/tutorials/plot_06_calcium_imaging.md b/docs/tutorials/plot_06_calcium_imaging.md index ef688398..c43091e3 100644 --- a/docs/tutorials/plot_06_calcium_imaging.md +++ b/docs/tutorials/plot_06_calcium_imaging.md @@ -364,7 +364,7 @@ from pathlib import Path path = Path("../assets/thumbnails/tutorials") if path.exists(): - fig.savefig(path / "plot_06_calcium_imaging.svg", metadata={"Date":""}) + fig.savefig(path / "plot_06_calcium_imaging.svg") ``` From 2d5f9962c71614117866a0c1572dfb86c619ca28 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 17:49:49 -0500 Subject: [PATCH 077/107] mod gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 858dc99b..514cff6f 100644 --- a/.gitignore +++ b/.gitignore @@ -154,5 +154,5 @@ docs/data/ docs/stubs # ignore the auto-generated svgs -docs/assets/thumbnails:wq +docs/assets/thumbnails From a7b3de96f06bc221004e8ea565021afc5fa595d4 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 18:13:46 -0500 Subject: [PATCH 078/107] linted --- docs/background/plot_01_1D_basis_function.md | 13 ++++++++++++- docs/background/plot_02_ND_basis_function.md | 13 ++++++++++++- docs/background/plot_03_1D_convolution.md | 13 ++++++++++++- docs/how_to_guide/plot_02_glm_demo.md | 13 ++++++++++++- docs/how_to_guide/plot_03_population_glm.md | 13 ++++++++++++- docs/how_to_guide/plot_04_batch_glm.md | 13 ++++++++++++- .../plot_05_sklearn_pipeline_cv_demo.md | 13 ++++++++++++- docs/how_to_guide/plot_06_glm_pytree.md | 13 ++++++++++++- docs/tutorials/plot_01_current_injection.md | 14 ++++++++++++-- docs/tutorials/plot_02_head_direction.md | 13 ++++++++++++- docs/tutorials/plot_03_grid_cells.md | 15 +++++++++++++-- docs/tutorials/plot_04_v1_cells.md | 13 ++++++++++++- docs/tutorials/plot_05_place_cells.md | 13 ++++++++++++- docs/tutorials/plot_06_calcium_imaging.md | 13 ++++++++++++- src/nemos/_documentation_utils/plotting.py | 2 +- 15 files changed, 170 insertions(+), 17 deletions(-) diff --git a/docs/background/plot_01_1D_basis_function.md b/docs/background/plot_01_1D_basis_function.md index 05edebe4..19e53f47 100644 --- a/docs/background/plot_01_1D_basis_function.md +++ b/docs/background/plot_01_1D_basis_function.md @@ -94,8 +94,19 @@ _ = plt.plot(eval_basis) # save image for thumbnail from pathlib import Path +import os + +root = os.environ.get("READTHEDOCS_OUTPUT") +if root: + path = Path(root) / "html/_static/thumbnails/background" +# if local store in assets +else: + path = Path("../assets/thumbnails/background") + +# make sure the folder exists if run from build +if root or Path("../assets").exists(): + path.mkdir(parents=True, exist_ok=True) -path = Path("../assets/thumbnails/background") if path.exists(): fig.savefig(path / "plot_01_1D_basis_function.svg") ``` diff --git a/docs/background/plot_02_ND_basis_function.md b/docs/background/plot_02_ND_basis_function.md index 84bbcdeb..5196a84e 100644 --- a/docs/background/plot_02_ND_basis_function.md +++ b/docs/background/plot_02_ND_basis_function.md @@ -298,8 +298,19 @@ plt.tight_layout() # save image for thumbnail from pathlib import Path +import os + +root = os.environ.get("READTHEDOCS_OUTPUT") +if root: + path = Path(root) / "html/_static/thumbnails/background" +# if local store in assets +else: + path = Path("../assets/thumbnails/background") + +# make sure the folder exists if run from build +if root or Path("../assets").exists(): + path.mkdir(parents=True, exist_ok=True) -path = Path("../assets/thumbnails/background") if path.exists(): fig.savefig(path / "plot_02_ND_basis_function.svg") ``` diff --git a/docs/background/plot_03_1D_convolution.md b/docs/background/plot_03_1D_convolution.md index 04faf528..591a4150 100644 --- a/docs/background/plot_03_1D_convolution.md +++ b/docs/background/plot_03_1D_convolution.md @@ -169,8 +169,19 @@ plt.tight_layout() # save image for thumbnail from pathlib import Path +import os + +root = os.environ.get("READTHEDOCS_OUTPUT") +if root: + path = Path(root) / "html/_static/thumbnails/background" +# if local store in assets +else: + path = Path("../assets/thumbnails/background") + +# make sure the folder exists if run from build +if root or Path("../assets").exists(): + path.mkdir(parents=True, exist_ok=True) -path = Path("../assets/thumbnails/background") if path.exists(): fig.savefig(path / "plot_03_1D_convolution.svg") ``` diff --git a/docs/how_to_guide/plot_02_glm_demo.md b/docs/how_to_guide/plot_02_glm_demo.md index bdad8fc1..c5bab115 100644 --- a/docs/how_to_guide/plot_02_glm_demo.md +++ b/docs/how_to_guide/plot_02_glm_demo.md @@ -439,8 +439,19 @@ plt.legend() # save image for thumbnail from pathlib import Path +import os + +root = os.environ.get("READTHEDOCS_OUTPUT") +if root: + path = Path(root) / "html/_static/thumbnails/how_to_guide" +# if local store in assets +else: + path = Path("../assets/thumbnails/how_to_guide") + +# make sure the folder exists if run from build +if root or Path("../assets").exists(): + path.mkdir(parents=True, exist_ok=True) -path = Path("../assets/thumbnails/how_to_guide") if path.exists(): fig.savefig(path / "plot_02_glm_demo.svg") ``` diff --git a/docs/how_to_guide/plot_03_population_glm.md b/docs/how_to_guide/plot_03_population_glm.md index 1239fed8..fdecb159 100644 --- a/docs/how_to_guide/plot_03_population_glm.md +++ b/docs/how_to_guide/plot_03_population_glm.md @@ -220,8 +220,19 @@ plt.tight_layout() # save image for thumbnail from pathlib import Path +import os + +root = os.environ.get("READTHEDOCS_OUTPUT") +if root: + path = Path(root) / "html/_static/thumbnails/how_to_guide" +# if local store in assets +else: + path = Path("../assets/thumbnails/how_to_guide") + +# make sure the folder exists if run from build +if root or Path("../assets").exists(): + path.mkdir(parents=True, exist_ok=True) -path = Path("../assets/thumbnails/how_to_guide") if path.exists(): fig.savefig(path / "plot_03_population_glm.svg") ``` diff --git a/docs/how_to_guide/plot_04_batch_glm.md b/docs/how_to_guide/plot_04_batch_glm.md index 63342acc..1699abf5 100644 --- a/docs/how_to_guide/plot_04_batch_glm.md +++ b/docs/how_to_guide/plot_04_batch_glm.md @@ -198,8 +198,19 @@ plt.show() # save image for thumbnail from pathlib import Path +import os + +root = os.environ.get("READTHEDOCS_OUTPUT") +if root: + path = Path(root) / "html/_static/thumbnails/how_to_guide" +# if local store in assets +else: + path = Path("../assets/thumbnails/how_to_guide") + +# make sure the folder exists if run from build +if root or Path("../assets").exists(): + path.mkdir(parents=True, exist_ok=True) -path = Path("../assets/thumbnails/how_to_guide") if path.exists(): fig.savefig(path / "plot_04_batch_glm.svg") ``` diff --git a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md index 170ab68b..754007d7 100644 --- a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md +++ b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md @@ -421,8 +421,19 @@ sns.despine(ax=ax) # save image for thumbnail from pathlib import Path +import os + +root = os.environ.get("READTHEDOCS_OUTPUT") +if root: + path = Path(root) / "html/_static/thumbnails/how_to_guide" +# if local store in assets +else: + path = Path("../assets/thumbnails/how_to_guide") + +# make sure the folder exists if run from build +if root or Path("../assets").exists(): + path.mkdir(parents=True, exist_ok=True) -path = Path("../assets/thumbnails/how_to_guide") if path.exists(): fig.savefig(path / "plot_05_sklearn_pipeline_cv_demo.svg") ``` diff --git a/docs/how_to_guide/plot_06_glm_pytree.md b/docs/how_to_guide/plot_06_glm_pytree.md index 58146377..b69854c8 100644 --- a/docs/how_to_guide/plot_06_glm_pytree.md +++ b/docs/how_to_guide/plot_06_glm_pytree.md @@ -251,8 +251,19 @@ axes[-1,-1].remove() # save image for thumbnail from pathlib import Path +import os + +root = os.environ.get("READTHEDOCS_OUTPUT") +if root: + path = Path(root) / "html/_static/thumbnails/how_to_guide" +# if local store in assets +else: + path = Path("../assets/thumbnails/how_to_guide") + +# make sure the folder exists if run from build +if root or Path("../assets").exists(): + path.mkdir(parents=True, exist_ok=True) -path = Path("../assets/thumbnails/how_to_guide") if path.exists(): fig.savefig(path / "plot_06_glm_pytree.svg") ``` diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md index 6f82cbd9..6d9a3049 100644 --- a/docs/tutorials/plot_01_current_injection.md +++ b/docs/tutorials/plot_01_current_injection.md @@ -623,9 +623,19 @@ fig = doc_plots.current_injection_plot(current, spikes, firing_rate, :tags: [hide-input] # save image for thumbnail -from pathlib import Path +import os + +root = os.environ.get("READTHEDOCS_OUTPUT") +if root: + path = Path(root) / "html/_static/thumbnails/tutorials" +# if local store in assets +else: + path = Path("../assets/thumbnails/tutorials") + +# make sure the folder exists if run from build +if root or Path("../assets").exists(): + path.mkdir(parents=True, exist_ok=True) -path = Path("../assets/thumbnails/tutorials") if path.exists(): fig.savefig(path / "plot_01_current_injection.svg") ``` diff --git a/docs/tutorials/plot_02_head_direction.md b/docs/tutorials/plot_02_head_direction.md index b6918bde..33d027f3 100644 --- a/docs/tutorials/plot_02_head_direction.md +++ b/docs/tutorials/plot_02_head_direction.md @@ -705,8 +705,19 @@ fig = doc_plots.plot_coupling(responses, tuning) # save image for thumbnail from pathlib import Path +import os + +root = os.environ.get("READTHEDOCS_OUTPUT") +if root: + path = Path(root) / "html/_static/thumbnails/tutorials" +# if local store in assets +else: + path = Path("../assets/thumbnails/tutorials") + +# make sure the folder exists if run from build +if root or Path("../assets").exists(): + path.mkdir(parents=True, exist_ok=True) -path = Path("../assets/thumbnails/tutorials") if path.exists(): fig.savefig(path / "plot_02_head_direction.svg") ``` \ No newline at end of file diff --git a/docs/tutorials/plot_03_grid_cells.md b/docs/tutorials/plot_03_grid_cells.md index 55e9dfee..6a4d9f15 100644 --- a/docs/tutorials/plot_03_grid_cells.md +++ b/docs/tutorials/plot_03_grid_cells.md @@ -334,8 +334,19 @@ plt.tight_layout() # save image for thumbnail from pathlib import Path - -path = Path("../assets/thumbnails/tutorials") +import os + +root = os.environ.get("READTHEDOCS_OUTPUT") +if root: + path = Path(root) / "html/_static/thumbnails/tutorials" +# if local store in assets +else: + path = Path("../assets/thumbnails/tutorials") + +# make sure the folder exists if run from build +if root or Path("../assets").exists(): + path.mkdir(parents=True, exist_ok=True) + if path.exists(): fig.savefig(path / "plot_03_grid_cells.svg") ``` \ No newline at end of file diff --git a/docs/tutorials/plot_04_v1_cells.md b/docs/tutorials/plot_04_v1_cells.md index d413a4be..39697713 100644 --- a/docs/tutorials/plot_04_v1_cells.md +++ b/docs/tutorials/plot_04_v1_cells.md @@ -237,8 +237,19 @@ ax.imshow(receptive_field, cmap='Greys_r') # save image for thumbnail from pathlib import Path +import os + +root = os.environ.get("READTHEDOCS_OUTPUT") +if root: + path = Path(root) / "html/_static/thumbnails/tutorials" +# if local store in assets +else: + path = Path("../assets/thumbnails/tutorials") + +# make sure the folder exists if run from build +if root or Path("../assets").exists(): + path.mkdir(parents=True, exist_ok=True) -path = Path("../assets/thumbnails/tutorials") if path.exists(): fig.savefig(path / "plot_04_v1_cells.svg") ``` diff --git a/docs/tutorials/plot_05_place_cells.md b/docs/tutorials/plot_05_place_cells.md index a8e80020..88c1d478 100644 --- a/docs/tutorials/plot_05_place_cells.md +++ b/docs/tutorials/plot_05_place_cells.md @@ -149,8 +149,19 @@ for i, n in enumerate(order): # save image for thumbnail from pathlib import Path +import os + +root = os.environ.get("READTHEDOCS_OUTPUT") +if root: + path = Path(root) / "html/_static/thumbnails/tutorials" +# if local store in assets +else: + path = Path("../assets/thumbnails/tutorials") + +# make sure the folder exists if run from build +if root or Path("../assets").exists(): + path.mkdir(parents=True, exist_ok=True) -path = Path("../assets/thumbnails/tutorials") if path.exists(): fig.savefig(path / "plot_05_place_cells.svg") ``` diff --git a/docs/tutorials/plot_06_calcium_imaging.md b/docs/tutorials/plot_06_calcium_imaging.md index c43091e3..5f0d3d6d 100644 --- a/docs/tutorials/plot_06_calcium_imaging.md +++ b/docs/tutorials/plot_06_calcium_imaging.md @@ -361,8 +361,19 @@ plt.show() # save image for thumbnail from pathlib import Path +import os + +root = os.environ.get("READTHEDOCS_OUTPUT") +if root: + path = Path(root) / "html/_static/thumbnails/tutorials" +# if local store in assets +else: + path = Path("../assets/thumbnails/tutorials") + +# make sure the folder exists if run from build +if root or Path("../assets").exists(): + path.mkdir(parents=True, exist_ok=True) -path = Path("../assets/thumbnails/tutorials") if path.exists(): fig.savefig(path / "plot_06_calcium_imaging.svg") ``` diff --git a/src/nemos/_documentation_utils/plotting.py b/src/nemos/_documentation_utils/plotting.py index c259e163..086ccb2c 100644 --- a/src/nemos/_documentation_utils/plotting.py +++ b/src/nemos/_documentation_utils/plotting.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -import os from typing import Optional, Union import jax @@ -41,6 +40,7 @@ "Feel free to use them, but they will probably not work as intended with other datasets / in other contexts." ) + def lnp_schematic( input_feature: nap.Tsd, weights: np.ndarray, From e0218cbc488b1583c15270b406be9a88d20b01c9 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 18:30:56 -0500 Subject: [PATCH 079/107] debug rtd --- .readthedocs.yaml | 3 +++ docs/post_build.py | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 docs/post_build.py diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 9487785e..e1c45847 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -13,7 +13,10 @@ build: jobs: pre_build: - gem install html-proofer -v ">= 5.0.9" # Ensure version >= 5.0.9 + - python -c "import os; print('READTHEDOCS_OUTPUT:', os.environ.get('READTHEDOCS_OUTPUT'))" post_build: + - python -c "import os; print('READTHEDOCS_OUTPUT:', os.environ.get('READTHEDOCS_OUTPUT'))" + - python post_build.py # Check everything except 403s and a jneurosci, which returns 404 but the link works when clicking. - htmlproofer $READTHEDOCS_OUTPUT/html --checks Links,Scripts,Images --ignore-urls "https://fonts.gstatic.com,https://www.jneurosci.org/content/25/47/11003" --assume-extension --check-external-hash --ignore-status-codes 403 --ignore-files "/.+\/_static\/.+/","/.+\/stubs\/.+/","/.+\/tutorials/plot_02_head_direction.+/" # The auto-generated animation doesn't have a alt or src/srcset; I am able to ignore missing alt, but I cannot work around a missing src/srcset diff --git a/docs/post_build.py b/docs/post_build.py new file mode 100644 index 00000000..9ee60031 --- /dev/null +++ b/docs/post_build.py @@ -0,0 +1,38 @@ +import os +from pathlib import Path +import matplotlib.pyplot as plt + +# Get the READTHEDOCS_OUTPUT environment variable +root = os.environ.get("READTHEDOCS_OUTPUT") + +if root: + # Define the paths + root_path = Path(root) + static_path = root_path / "html/_static" + target_path = static_path / "thumbnails/how_to_guide" + + # Check if both directories exist + if static_path.exists() and target_path.exists(): + print(f"Both {static_path} and {target_path} exist. Plotting...") + + # Generate a sample plot + plt.figure() + plt.plot([1, 2, 3], [4, 5, 6], label="Sample Plot") + plt.legend() + plt.title("Post-Build Plot") + + # Save the plot in the target directory + plot_path = target_path / "post_build_plot.svg" + plt.savefig(plot_path) + print(f"Plot saved to {plot_path}") + + print(f"\nContents of {target_path}:") + for item in target_path.iterdir(): + if item.is_file(): + print(f"- File: {item.name}") + elif item.is_dir(): + print(f"- Directory: {item.name}") + else: + print(f"Either {static_path} or {target_path} does not exist.") +else: + print("READTHEDOCS_OUTPUT is not set. Skipping plot generation.") From 99a049e4e8723239a481836ad837db17e54d32ab Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 18:36:56 -0500 Subject: [PATCH 080/107] add a prebuild debug --- .readthedocs.yaml | 4 ++-- docs/pre_build.py | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 docs/pre_build.py diff --git a/.readthedocs.yaml b/.readthedocs.yaml index e1c45847..3deff1be 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -13,9 +13,9 @@ build: jobs: pre_build: - gem install html-proofer -v ">= 5.0.9" # Ensure version >= 5.0.9 - - python -c "import os; print('READTHEDOCS_OUTPUT:', os.environ.get('READTHEDOCS_OUTPUT'))" + - python pre_build.py post_build: - - python -c "import os; print('READTHEDOCS_OUTPUT:', os.environ.get('READTHEDOCS_OUTPUT'))" + - python pre_build.py - python post_build.py # Check everything except 403s and a jneurosci, which returns 404 but the link works when clicking. - htmlproofer $READTHEDOCS_OUTPUT/html --checks Links,Scripts,Images --ignore-urls "https://fonts.gstatic.com,https://www.jneurosci.org/content/25/47/11003" --assume-extension --check-external-hash --ignore-status-codes 403 --ignore-files "/.+\/_static\/.+/","/.+\/stubs\/.+/","/.+\/tutorials/plot_02_head_direction.+/" diff --git a/docs/pre_build.py b/docs/pre_build.py new file mode 100644 index 00000000..9cd2a52f --- /dev/null +++ b/docs/pre_build.py @@ -0,0 +1,21 @@ +import os +from pathlib import Path + +# Get the READTHEDOCS_OUTPUT environment variable +rtd_output = os.environ.get("READTHEDOCS_OUTPUT") + +if rtd_output: + print(f"READTHEDOCS_OUTPUT is set: {rtd_output}") + + # Convert to a Path object for better handling + output_path = Path(rtd_output) + print(f"Path resolved as: {output_path}") + + # Example: Check if it exists + if output_path.exists(): + print(f"The path exists: {output_path}") + else: + print(f"The path does not exist: {output_path}") + +else: + print("READTHEDOCS_OUTPUT is not set.") From 80d95ef312ecbbc648f299eb3b903d6a6a6c11ab Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 18:39:13 -0500 Subject: [PATCH 081/107] fix rtd --- .readthedocs.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 3deff1be..a74d45cb 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -13,10 +13,10 @@ build: jobs: pre_build: - gem install html-proofer -v ">= 5.0.9" # Ensure version >= 5.0.9 - - python pre_build.py + - python docs/pre_build.py post_build: - - python pre_build.py - - python post_build.py + - python docs/pre_build.py + - python docs/post_build.py # Check everything except 403s and a jneurosci, which returns 404 but the link works when clicking. - htmlproofer $READTHEDOCS_OUTPUT/html --checks Links,Scripts,Images --ignore-urls "https://fonts.gstatic.com,https://www.jneurosci.org/content/25/47/11003" --assume-extension --check-external-hash --ignore-status-codes 403 --ignore-files "/.+\/_static\/.+/","/.+\/stubs\/.+/","/.+\/tutorials/plot_02_head_direction.+/" # The auto-generated animation doesn't have a alt or src/srcset; I am able to ignore missing alt, but I cannot work around a missing src/srcset From 1a4a8a5fe1e21d8943e7b9df85762cc2a9f5ce02 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 18:50:52 -0500 Subject: [PATCH 082/107] thumbnail added --- .../background/plot_00_conceptual_intro.svg | 415 ++++++++++++++++++ 1 file changed, 415 insertions(+) create mode 100644 docs/assets/thumbnails/background/plot_00_conceptual_intro.svg diff --git a/docs/assets/thumbnails/background/plot_00_conceptual_intro.svg b/docs/assets/thumbnails/background/plot_00_conceptual_intro.svg new file mode 100644 index 00000000..6757f795 --- /dev/null +++ b/docs/assets/thumbnails/background/plot_00_conceptual_intro.svg @@ -0,0 +1,415 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e + x + + Nonlinearity + Linear filter + + + + + + + Poisson + Spikes + Input + GLM model + + From 12f675c6e5b13af88729dd1e5e1b80deaec7eba9 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 18:53:51 -0500 Subject: [PATCH 083/107] change to save in assets --- docs/background/plot_01_1D_basis_function.md | 2 +- docs/background/plot_02_ND_basis_function.md | 2 +- docs/background/plot_03_1D_convolution.md | 2 +- docs/how_to_guide/plot_02_glm_demo.md | 2 +- docs/how_to_guide/plot_03_population_glm.md | 2 +- docs/how_to_guide/plot_04_batch_glm.md | 2 +- docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md | 2 +- docs/how_to_guide/plot_06_glm_pytree.md | 2 +- docs/tutorials/plot_01_current_injection.md | 2 +- docs/tutorials/plot_02_head_direction.md | 2 +- docs/tutorials/plot_03_grid_cells.md | 2 +- docs/tutorials/plot_04_v1_cells.md | 2 +- docs/tutorials/plot_05_place_cells.md | 2 +- docs/tutorials/plot_06_calcium_imaging.md | 4 ++-- 14 files changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/background/plot_01_1D_basis_function.md b/docs/background/plot_01_1D_basis_function.md index 19e53f47..3ff3bcc7 100644 --- a/docs/background/plot_01_1D_basis_function.md +++ b/docs/background/plot_01_1D_basis_function.md @@ -98,7 +98,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path(root) / "html/_static/thumbnails/background" + path = Path("docs/assets/thumbnails/background") # if local store in assets else: path = Path("../assets/thumbnails/background") diff --git a/docs/background/plot_02_ND_basis_function.md b/docs/background/plot_02_ND_basis_function.md index 5196a84e..90f725e5 100644 --- a/docs/background/plot_02_ND_basis_function.md +++ b/docs/background/plot_02_ND_basis_function.md @@ -302,7 +302,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path(root) / "html/_static/thumbnails/background" + path = Path("docs/assets/thumbnails/background") # if local store in assets else: path = Path("../assets/thumbnails/background") diff --git a/docs/background/plot_03_1D_convolution.md b/docs/background/plot_03_1D_convolution.md index 591a4150..54953293 100644 --- a/docs/background/plot_03_1D_convolution.md +++ b/docs/background/plot_03_1D_convolution.md @@ -173,7 +173,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path(root) / "html/_static/thumbnails/background" + path = Path("docs/assets/thumbnails/background") # if local store in assets else: path = Path("../assets/thumbnails/background") diff --git a/docs/how_to_guide/plot_02_glm_demo.md b/docs/how_to_guide/plot_02_glm_demo.md index c5bab115..a2525900 100644 --- a/docs/how_to_guide/plot_02_glm_demo.md +++ b/docs/how_to_guide/plot_02_glm_demo.md @@ -443,7 +443,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path(root) / "html/_static/thumbnails/how_to_guide" + path = Path("docs/assets/thumbnails/how_to_guide") # if local store in assets else: path = Path("../assets/thumbnails/how_to_guide") diff --git a/docs/how_to_guide/plot_03_population_glm.md b/docs/how_to_guide/plot_03_population_glm.md index fdecb159..31dadcc4 100644 --- a/docs/how_to_guide/plot_03_population_glm.md +++ b/docs/how_to_guide/plot_03_population_glm.md @@ -224,7 +224,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path(root) / "html/_static/thumbnails/how_to_guide" + path = Path("docs/assets/thumbnails/how_to_guide") # if local store in assets else: path = Path("../assets/thumbnails/how_to_guide") diff --git a/docs/how_to_guide/plot_04_batch_glm.md b/docs/how_to_guide/plot_04_batch_glm.md index 1699abf5..f3760bb6 100644 --- a/docs/how_to_guide/plot_04_batch_glm.md +++ b/docs/how_to_guide/plot_04_batch_glm.md @@ -202,7 +202,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path(root) / "html/_static/thumbnails/how_to_guide" + path = Path("docs/assets/thumbnails/how_to_guide") # if local store in assets else: path = Path("../assets/thumbnails/how_to_guide") diff --git a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md index 754007d7..376b36c4 100644 --- a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md +++ b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md @@ -425,7 +425,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path(root) / "html/_static/thumbnails/how_to_guide" + path = Path("docs/assets/thumbnails/how_to_guide") # if local store in assets else: path = Path("../assets/thumbnails/how_to_guide") diff --git a/docs/how_to_guide/plot_06_glm_pytree.md b/docs/how_to_guide/plot_06_glm_pytree.md index b69854c8..0796e5fb 100644 --- a/docs/how_to_guide/plot_06_glm_pytree.md +++ b/docs/how_to_guide/plot_06_glm_pytree.md @@ -255,7 +255,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path(root) / "html/_static/thumbnails/how_to_guide" + path = Path("docs/assets/thumbnails/how_to_guide") # if local store in assets else: path = Path("../assets/thumbnails/how_to_guide") diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md index 6d9a3049..c5946afc 100644 --- a/docs/tutorials/plot_01_current_injection.md +++ b/docs/tutorials/plot_01_current_injection.md @@ -627,7 +627,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path(root) / "html/_static/thumbnails/tutorials" + path = Path("docs/assets/thumbnails/tutorials") # if local store in assets else: path = Path("../assets/thumbnails/tutorials") diff --git a/docs/tutorials/plot_02_head_direction.md b/docs/tutorials/plot_02_head_direction.md index 33d027f3..dc33e784 100644 --- a/docs/tutorials/plot_02_head_direction.md +++ b/docs/tutorials/plot_02_head_direction.md @@ -709,7 +709,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path(root) / "html/_static/thumbnails/tutorials" + path = Path("docs/assets/thumbnails/tutorials") # if local store in assets else: path = Path("../assets/thumbnails/tutorials") diff --git a/docs/tutorials/plot_03_grid_cells.md b/docs/tutorials/plot_03_grid_cells.md index 6a4d9f15..884a5d74 100644 --- a/docs/tutorials/plot_03_grid_cells.md +++ b/docs/tutorials/plot_03_grid_cells.md @@ -338,7 +338,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path(root) / "html/_static/thumbnails/tutorials" + path = Path("docs/assets/thumbnails/tutorials") # if local store in assets else: path = Path("../assets/thumbnails/tutorials") diff --git a/docs/tutorials/plot_04_v1_cells.md b/docs/tutorials/plot_04_v1_cells.md index 39697713..af2ca279 100644 --- a/docs/tutorials/plot_04_v1_cells.md +++ b/docs/tutorials/plot_04_v1_cells.md @@ -241,7 +241,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path(root) / "html/_static/thumbnails/tutorials" + path = Path("docs/assets/thumbnails/tutorials") # if local store in assets else: path = Path("../assets/thumbnails/tutorials") diff --git a/docs/tutorials/plot_05_place_cells.md b/docs/tutorials/plot_05_place_cells.md index 88c1d478..2edd6385 100644 --- a/docs/tutorials/plot_05_place_cells.md +++ b/docs/tutorials/plot_05_place_cells.md @@ -153,7 +153,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path(root) / "html/_static/thumbnails/tutorials" + path = Path("docs/assets/thumbnails/tutorials") # if local store in assets else: path = Path("../assets/thumbnails/tutorials") diff --git a/docs/tutorials/plot_06_calcium_imaging.md b/docs/tutorials/plot_06_calcium_imaging.md index 5f0d3d6d..41e2be9f 100644 --- a/docs/tutorials/plot_06_calcium_imaging.md +++ b/docs/tutorials/plot_06_calcium_imaging.md @@ -195,7 +195,7 @@ basis = heading_basis + coupling_basis ## Gamma GLM Until now, we have been modeling spike trains, and have used a Poisson distribution for the observation model. With calcium traces, things are quite different: we no longer have counts but continuous signals, so the Poisson assumption is no longer appropriate. A Gaussian model is also not ideal since the calcium traces are non-negative. To satisfy these constraints, we will use a Gamma distribution from NeMoS with a soft-plus non linearity. -:::{admonirion} Non-linearity +:::{admonition} Non-linearity :class: note Different option are possible. With a soft-plus we are assuming an "additive" effect of the predictors, while an exponential non-linearity assumes multiplicative effects. Deciding which firing rate model works best is an empirical question. You can fit different configurations to see which one capture best the neural activity. @@ -365,7 +365,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path(root) / "html/_static/thumbnails/tutorials" + path = Path("docs/assets/thumbnails/tutorials") # if local store in assets else: path = Path("../assets/thumbnails/tutorials") From cc9e81308d014aec6fe39784912264045f22a8ad Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 18:55:52 -0500 Subject: [PATCH 084/107] Revert "thumbnail added" This reverts commit 1a4a8a5fe1e21d8943e7b9df85762cc2a9f5ce02. --- .../background/plot_00_conceptual_intro.svg | 415 ------------------ 1 file changed, 415 deletions(-) delete mode 100644 docs/assets/thumbnails/background/plot_00_conceptual_intro.svg diff --git a/docs/assets/thumbnails/background/plot_00_conceptual_intro.svg b/docs/assets/thumbnails/background/plot_00_conceptual_intro.svg deleted file mode 100644 index 6757f795..00000000 --- a/docs/assets/thumbnails/background/plot_00_conceptual_intro.svg +++ /dev/null @@ -1,415 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - e - x - - Nonlinearity - Linear filter - - - - - - - Poisson - Spikes - Input - GLM model - - From bf83f9456837e7efb73cd66c473fafcf43b327a9 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 18:56:30 -0500 Subject: [PATCH 085/107] Revert "change to save in assets" This reverts commit 12f675c6e5b13af88729dd1e5e1b80deaec7eba9. --- docs/background/plot_01_1D_basis_function.md | 2 +- docs/background/plot_02_ND_basis_function.md | 2 +- docs/background/plot_03_1D_convolution.md | 2 +- docs/how_to_guide/plot_02_glm_demo.md | 2 +- docs/how_to_guide/plot_03_population_glm.md | 2 +- docs/how_to_guide/plot_04_batch_glm.md | 2 +- docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md | 2 +- docs/how_to_guide/plot_06_glm_pytree.md | 2 +- docs/tutorials/plot_01_current_injection.md | 2 +- docs/tutorials/plot_02_head_direction.md | 2 +- docs/tutorials/plot_03_grid_cells.md | 2 +- docs/tutorials/plot_04_v1_cells.md | 2 +- docs/tutorials/plot_05_place_cells.md | 2 +- docs/tutorials/plot_06_calcium_imaging.md | 4 ++-- 14 files changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/background/plot_01_1D_basis_function.md b/docs/background/plot_01_1D_basis_function.md index 3ff3bcc7..19e53f47 100644 --- a/docs/background/plot_01_1D_basis_function.md +++ b/docs/background/plot_01_1D_basis_function.md @@ -98,7 +98,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path("docs/assets/thumbnails/background") + path = Path(root) / "html/_static/thumbnails/background" # if local store in assets else: path = Path("../assets/thumbnails/background") diff --git a/docs/background/plot_02_ND_basis_function.md b/docs/background/plot_02_ND_basis_function.md index 90f725e5..5196a84e 100644 --- a/docs/background/plot_02_ND_basis_function.md +++ b/docs/background/plot_02_ND_basis_function.md @@ -302,7 +302,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path("docs/assets/thumbnails/background") + path = Path(root) / "html/_static/thumbnails/background" # if local store in assets else: path = Path("../assets/thumbnails/background") diff --git a/docs/background/plot_03_1D_convolution.md b/docs/background/plot_03_1D_convolution.md index 54953293..591a4150 100644 --- a/docs/background/plot_03_1D_convolution.md +++ b/docs/background/plot_03_1D_convolution.md @@ -173,7 +173,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path("docs/assets/thumbnails/background") + path = Path(root) / "html/_static/thumbnails/background" # if local store in assets else: path = Path("../assets/thumbnails/background") diff --git a/docs/how_to_guide/plot_02_glm_demo.md b/docs/how_to_guide/plot_02_glm_demo.md index a2525900..c5bab115 100644 --- a/docs/how_to_guide/plot_02_glm_demo.md +++ b/docs/how_to_guide/plot_02_glm_demo.md @@ -443,7 +443,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path("docs/assets/thumbnails/how_to_guide") + path = Path(root) / "html/_static/thumbnails/how_to_guide" # if local store in assets else: path = Path("../assets/thumbnails/how_to_guide") diff --git a/docs/how_to_guide/plot_03_population_glm.md b/docs/how_to_guide/plot_03_population_glm.md index 31dadcc4..fdecb159 100644 --- a/docs/how_to_guide/plot_03_population_glm.md +++ b/docs/how_to_guide/plot_03_population_glm.md @@ -224,7 +224,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path("docs/assets/thumbnails/how_to_guide") + path = Path(root) / "html/_static/thumbnails/how_to_guide" # if local store in assets else: path = Path("../assets/thumbnails/how_to_guide") diff --git a/docs/how_to_guide/plot_04_batch_glm.md b/docs/how_to_guide/plot_04_batch_glm.md index f3760bb6..1699abf5 100644 --- a/docs/how_to_guide/plot_04_batch_glm.md +++ b/docs/how_to_guide/plot_04_batch_glm.md @@ -202,7 +202,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path("docs/assets/thumbnails/how_to_guide") + path = Path(root) / "html/_static/thumbnails/how_to_guide" # if local store in assets else: path = Path("../assets/thumbnails/how_to_guide") diff --git a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md index 376b36c4..754007d7 100644 --- a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md +++ b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md @@ -425,7 +425,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path("docs/assets/thumbnails/how_to_guide") + path = Path(root) / "html/_static/thumbnails/how_to_guide" # if local store in assets else: path = Path("../assets/thumbnails/how_to_guide") diff --git a/docs/how_to_guide/plot_06_glm_pytree.md b/docs/how_to_guide/plot_06_glm_pytree.md index 0796e5fb..b69854c8 100644 --- a/docs/how_to_guide/plot_06_glm_pytree.md +++ b/docs/how_to_guide/plot_06_glm_pytree.md @@ -255,7 +255,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path("docs/assets/thumbnails/how_to_guide") + path = Path(root) / "html/_static/thumbnails/how_to_guide" # if local store in assets else: path = Path("../assets/thumbnails/how_to_guide") diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md index c5946afc..6d9a3049 100644 --- a/docs/tutorials/plot_01_current_injection.md +++ b/docs/tutorials/plot_01_current_injection.md @@ -627,7 +627,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path("docs/assets/thumbnails/tutorials") + path = Path(root) / "html/_static/thumbnails/tutorials" # if local store in assets else: path = Path("../assets/thumbnails/tutorials") diff --git a/docs/tutorials/plot_02_head_direction.md b/docs/tutorials/plot_02_head_direction.md index dc33e784..33d027f3 100644 --- a/docs/tutorials/plot_02_head_direction.md +++ b/docs/tutorials/plot_02_head_direction.md @@ -709,7 +709,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path("docs/assets/thumbnails/tutorials") + path = Path(root) / "html/_static/thumbnails/tutorials" # if local store in assets else: path = Path("../assets/thumbnails/tutorials") diff --git a/docs/tutorials/plot_03_grid_cells.md b/docs/tutorials/plot_03_grid_cells.md index 884a5d74..6a4d9f15 100644 --- a/docs/tutorials/plot_03_grid_cells.md +++ b/docs/tutorials/plot_03_grid_cells.md @@ -338,7 +338,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path("docs/assets/thumbnails/tutorials") + path = Path(root) / "html/_static/thumbnails/tutorials" # if local store in assets else: path = Path("../assets/thumbnails/tutorials") diff --git a/docs/tutorials/plot_04_v1_cells.md b/docs/tutorials/plot_04_v1_cells.md index af2ca279..39697713 100644 --- a/docs/tutorials/plot_04_v1_cells.md +++ b/docs/tutorials/plot_04_v1_cells.md @@ -241,7 +241,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path("docs/assets/thumbnails/tutorials") + path = Path(root) / "html/_static/thumbnails/tutorials" # if local store in assets else: path = Path("../assets/thumbnails/tutorials") diff --git a/docs/tutorials/plot_05_place_cells.md b/docs/tutorials/plot_05_place_cells.md index 2edd6385..88c1d478 100644 --- a/docs/tutorials/plot_05_place_cells.md +++ b/docs/tutorials/plot_05_place_cells.md @@ -153,7 +153,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path("docs/assets/thumbnails/tutorials") + path = Path(root) / "html/_static/thumbnails/tutorials" # if local store in assets else: path = Path("../assets/thumbnails/tutorials") diff --git a/docs/tutorials/plot_06_calcium_imaging.md b/docs/tutorials/plot_06_calcium_imaging.md index 41e2be9f..5f0d3d6d 100644 --- a/docs/tutorials/plot_06_calcium_imaging.md +++ b/docs/tutorials/plot_06_calcium_imaging.md @@ -195,7 +195,7 @@ basis = heading_basis + coupling_basis ## Gamma GLM Until now, we have been modeling spike trains, and have used a Poisson distribution for the observation model. With calcium traces, things are quite different: we no longer have counts but continuous signals, so the Poisson assumption is no longer appropriate. A Gaussian model is also not ideal since the calcium traces are non-negative. To satisfy these constraints, we will use a Gamma distribution from NeMoS with a soft-plus non linearity. -:::{admonition} Non-linearity +:::{admonirion} Non-linearity :class: note Different option are possible. With a soft-plus we are assuming an "additive" effect of the predictors, while an exponential non-linearity assumes multiplicative effects. Deciding which firing rate model works best is an empirical question. You can fit different configurations to see which one capture best the neural activity. @@ -365,7 +365,7 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: - path = Path("docs/assets/thumbnails/tutorials") + path = Path(root) / "html/_static/thumbnails/tutorials" # if local store in assets else: path = Path("../assets/thumbnails/tutorials") From 627db1de1503bce78ef76393b8df88636020f6a8 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 18:59:44 -0500 Subject: [PATCH 086/107] reverted to save to static --- docs/tutorials/plot_06_calcium_imaging.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/plot_06_calcium_imaging.md b/docs/tutorials/plot_06_calcium_imaging.md index 5f0d3d6d..237c1926 100644 --- a/docs/tutorials/plot_06_calcium_imaging.md +++ b/docs/tutorials/plot_06_calcium_imaging.md @@ -195,7 +195,7 @@ basis = heading_basis + coupling_basis ## Gamma GLM Until now, we have been modeling spike trains, and have used a Poisson distribution for the observation model. With calcium traces, things are quite different: we no longer have counts but continuous signals, so the Poisson assumption is no longer appropriate. A Gaussian model is also not ideal since the calcium traces are non-negative. To satisfy these constraints, we will use a Gamma distribution from NeMoS with a soft-plus non linearity. -:::{admonirion} Non-linearity +:::{admonition} Non-linearity :class: note Different option are possible. With a soft-plus we are assuming an "additive" effect of the predictors, while an exponential non-linearity assumes multiplicative effects. Deciding which firing rate model works best is an empirical question. You can fit different configurations to see which one capture best the neural activity. From 92bc20b750265297339b99bc04cf21b8e0c03e8f Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 19:02:02 -0500 Subject: [PATCH 087/107] increase timeout --- docs/conf.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index 94a3948d..96ee47c9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -147,4 +147,6 @@ sphinxemoji_style = 'twemoji' +nb_execution_timeout = 60 * 15 # Set timeout in seconds (e.g., 15 minutes) + nitpicky = True From 6e4a08cdc5a21b7742d3090818c48b273ace6e13 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 19:04:35 -0500 Subject: [PATCH 088/107] changed image --- docs/background/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/background/README.md b/docs/background/README.md index 13e7b3a7..3215c329 100644 --- a/docs/background/README.md +++ b/docs/background/README.md @@ -20,7 +20,7 @@ pip install nemos[examples] :::{grid-item-card}
-Linear-Non Linear-Poisson illustration. +Linear-Non Linear-Poisson illustration.
From 774a79f4275ad713703d561da7f704c79decc4a1 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 21 Nov 2024 19:31:49 -0500 Subject: [PATCH 089/107] added ipython kernel --- pyproject.toml | 1 + src/nemos/fetch/fetch_data.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 6cc3681f..1937d7d3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -79,6 +79,7 @@ docs = [ "seaborn", "pooch", "ipywidgets", + "ipykernel", ] examples = [ "scikit-learn", diff --git a/src/nemos/fetch/fetch_data.py b/src/nemos/fetch/fetch_data.py index aadb44b7..560500b8 100644 --- a/src/nemos/fetch/fetch_data.py +++ b/src/nemos/fetch/fetch_data.py @@ -11,6 +11,7 @@ import pathlib from typing import Optional, Union + try: import pooch from pooch import Pooch @@ -18,6 +19,7 @@ except ImportError: pooch = None Pooch = None + tqdm = None try: import dandi From beca7bedbec3078b1392982ef9093da24550732c Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 22 Nov 2024 10:57:09 -0500 Subject: [PATCH 090/107] fixed progress bar --- docs/background/plot_01_1D_basis_function.md | 6 +++--- docs/background/plot_02_ND_basis_function.md | 6 +++--- docs/background/plot_03_1D_convolution.md | 6 +++--- docs/how_to_guide/plot_02_glm_demo.md | 6 +++--- docs/how_to_guide/plot_03_population_glm.md | 6 +++--- docs/how_to_guide/plot_04_batch_glm.md | 6 +++--- docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md | 6 +++--- docs/how_to_guide/plot_06_glm_pytree.md | 6 +++--- docs/tutorials/plot_01_current_injection.md | 4 ++-- docs/tutorials/plot_02_head_direction.md | 4 ++-- docs/tutorials/plot_03_grid_cells.md | 6 +++--- docs/tutorials/plot_04_v1_cells.md | 4 ++-- docs/tutorials/plot_05_place_cells.md | 4 ++-- docs/tutorials/plot_06_calcium_imaging.md | 4 ++-- src/nemos/fetch/fetch_data.py | 4 ++-- 15 files changed, 39 insertions(+), 39 deletions(-) diff --git a/docs/background/plot_01_1D_basis_function.md b/docs/background/plot_01_1D_basis_function.md index 19e53f47..4b70cd8f 100644 --- a/docs/background/plot_01_1D_basis_function.md +++ b/docs/background/plot_01_1D_basis_function.md @@ -99,12 +99,12 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: path = Path(root) / "html/_static/thumbnails/background" -# if local store in assets +# if local store in ../_build/html/... else: - path = Path("../assets/thumbnails/background") + path = Path("../_build/html/_static/thumbnails/background") # make sure the folder exists if run from build -if root or Path("../assets").exists(): +if root or Path("../_build/html/_static/thumbnails").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/background/plot_02_ND_basis_function.md b/docs/background/plot_02_ND_basis_function.md index 5196a84e..23338951 100644 --- a/docs/background/plot_02_ND_basis_function.md +++ b/docs/background/plot_02_ND_basis_function.md @@ -303,12 +303,12 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: path = Path(root) / "html/_static/thumbnails/background" -# if local store in assets +# if local store in ../_build/html/... else: - path = Path("../assets/thumbnails/background") + path = Path("../_build/html/_static/thumbnails/background") # make sure the folder exists if run from build -if root or Path("../assets").exists(): +if root or Path("../_build/html/_static/thumbnails").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/background/plot_03_1D_convolution.md b/docs/background/plot_03_1D_convolution.md index 591a4150..bbf1a8a7 100644 --- a/docs/background/plot_03_1D_convolution.md +++ b/docs/background/plot_03_1D_convolution.md @@ -174,12 +174,12 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: path = Path(root) / "html/_static/thumbnails/background" -# if local store in assets +# if local store in ../_build/html/... else: - path = Path("../assets/thumbnails/background") + path = Path("../_build/html/_static/thumbnails/background") # make sure the folder exists if run from build -if root or Path("../assets").exists(): +if root or Path("../_build/html/_static/thumbnails").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/how_to_guide/plot_02_glm_demo.md b/docs/how_to_guide/plot_02_glm_demo.md index c5bab115..83c400a9 100644 --- a/docs/how_to_guide/plot_02_glm_demo.md +++ b/docs/how_to_guide/plot_02_glm_demo.md @@ -444,12 +444,12 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: path = Path(root) / "html/_static/thumbnails/how_to_guide" -# if local store in assets +# if local store in ../_build/html/... else: - path = Path("../assets/thumbnails/how_to_guide") + path = Path("../_build/html/_static/thumbnails/how_to_guide") # make sure the folder exists if run from build -if root or Path("../assets").exists(): +if root or Path("../_build/html/_static/thumbnails").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/how_to_guide/plot_03_population_glm.md b/docs/how_to_guide/plot_03_population_glm.md index fdecb159..611c43a9 100644 --- a/docs/how_to_guide/plot_03_population_glm.md +++ b/docs/how_to_guide/plot_03_population_glm.md @@ -225,12 +225,12 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: path = Path(root) / "html/_static/thumbnails/how_to_guide" -# if local store in assets +# if local store in ../_build/html/... else: - path = Path("../assets/thumbnails/how_to_guide") + path = Path("../_build/html/_static/thumbnails/how_to_guide") # make sure the folder exists if run from build -if root or Path("../assets").exists(): +if root or Path("../_build/html/_static/thumbnails").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/how_to_guide/plot_04_batch_glm.md b/docs/how_to_guide/plot_04_batch_glm.md index 1699abf5..5de99c1f 100644 --- a/docs/how_to_guide/plot_04_batch_glm.md +++ b/docs/how_to_guide/plot_04_batch_glm.md @@ -203,12 +203,12 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: path = Path(root) / "html/_static/thumbnails/how_to_guide" -# if local store in assets +# if local store in ../_build/html/... else: - path = Path("../assets/thumbnails/how_to_guide") + path = Path("../_build/html/_static/thumbnails/how_to_guide") # make sure the folder exists if run from build -if root or Path("../assets").exists(): +if root or Path("../_build/html/_static/thumbnails").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md index 754007d7..6072582c 100644 --- a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md +++ b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md @@ -426,12 +426,12 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: path = Path(root) / "html/_static/thumbnails/how_to_guide" -# if local store in assets +# if local store in ../_build/html/... else: - path = Path("../assets/thumbnails/how_to_guide") + path = Path("../_build/html/_static/thumbnails/how_to_guide") # make sure the folder exists if run from build -if root or Path("../assets").exists(): +if root or Path("../_build/html/_static/thumbnails").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/how_to_guide/plot_06_glm_pytree.md b/docs/how_to_guide/plot_06_glm_pytree.md index b69854c8..7110fb59 100644 --- a/docs/how_to_guide/plot_06_glm_pytree.md +++ b/docs/how_to_guide/plot_06_glm_pytree.md @@ -256,12 +256,12 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: path = Path(root) / "html/_static/thumbnails/how_to_guide" -# if local store in assets +# if local store in ../_build/html/... else: - path = Path("../assets/thumbnails/how_to_guide") + path = Path("../_build/html/_static/thumbnails/how_to_guide") # make sure the folder exists if run from build -if root or Path("../assets").exists(): +if root or Path("../_build/html/_static/thumbnails").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md index 6d9a3049..bfc81e4d 100644 --- a/docs/tutorials/plot_01_current_injection.md +++ b/docs/tutorials/plot_01_current_injection.md @@ -630,10 +630,10 @@ if root: path = Path(root) / "html/_static/thumbnails/tutorials" # if local store in assets else: - path = Path("../assets/thumbnails/tutorials") + path = Path("../_build/html/_static/thumbnails/tutorials") # make sure the folder exists if run from build -if root or Path("../assets").exists(): +if root or Path("../_build/html/_static/thumbnails").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/tutorials/plot_02_head_direction.md b/docs/tutorials/plot_02_head_direction.md index 33d027f3..9cf9d992 100644 --- a/docs/tutorials/plot_02_head_direction.md +++ b/docs/tutorials/plot_02_head_direction.md @@ -712,10 +712,10 @@ if root: path = Path(root) / "html/_static/thumbnails/tutorials" # if local store in assets else: - path = Path("../assets/thumbnails/tutorials") + path = Path("../_build/html/_static/thumbnails/tutorials") # make sure the folder exists if run from build -if root or Path("../assets").exists(): +if root or Path("../_build/html/_static/thumbnails").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/tutorials/plot_03_grid_cells.md b/docs/tutorials/plot_03_grid_cells.md index 6a4d9f15..c3149a22 100644 --- a/docs/tutorials/plot_03_grid_cells.md +++ b/docs/tutorials/plot_03_grid_cells.md @@ -339,12 +339,12 @@ import os root = os.environ.get("READTHEDOCS_OUTPUT") if root: path = Path(root) / "html/_static/thumbnails/tutorials" -# if local store in assets +# if local store in ../_build/html... else: - path = Path("../assets/thumbnails/tutorials") + path = Path("../_build/html/_static/thumbnails/tutorials") # make sure the folder exists if run from build -if root or Path("../assets").exists(): +if root or Path("../_build/html/_static/thumbnails").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/tutorials/plot_04_v1_cells.md b/docs/tutorials/plot_04_v1_cells.md index 39697713..e3d38bf6 100644 --- a/docs/tutorials/plot_04_v1_cells.md +++ b/docs/tutorials/plot_04_v1_cells.md @@ -244,10 +244,10 @@ if root: path = Path(root) / "html/_static/thumbnails/tutorials" # if local store in assets else: - path = Path("../assets/thumbnails/tutorials") + path = Path("../_build/html/_static/thumbnails/tutorials") # make sure the folder exists if run from build -if root or Path("../assets").exists(): +if root or Path("../_build/html/_static/thumbnails").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/tutorials/plot_05_place_cells.md b/docs/tutorials/plot_05_place_cells.md index 88c1d478..9a57f36e 100644 --- a/docs/tutorials/plot_05_place_cells.md +++ b/docs/tutorials/plot_05_place_cells.md @@ -156,10 +156,10 @@ if root: path = Path(root) / "html/_static/thumbnails/tutorials" # if local store in assets else: - path = Path("../assets/thumbnails/tutorials") + path = Path("../_build/html/_static/thumbnails/tutorials") # make sure the folder exists if run from build -if root or Path("../assets").exists(): +if root or Path("../_build/html/_static/thumbnails").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/tutorials/plot_06_calcium_imaging.md b/docs/tutorials/plot_06_calcium_imaging.md index 237c1926..2b289b55 100644 --- a/docs/tutorials/plot_06_calcium_imaging.md +++ b/docs/tutorials/plot_06_calcium_imaging.md @@ -368,10 +368,10 @@ if root: path = Path(root) / "html/_static/thumbnails/tutorials" # if local store in assets else: - path = Path("../assets/thumbnails/tutorials") + path = Path("../_build/html/_static/thumbnails/tutorials") # make sure the folder exists if run from build -if root or Path("../assets").exists(): +if root or Path("../_build/html/_static/thumbnails").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/src/nemos/fetch/fetch_data.py b/src/nemos/fetch/fetch_data.py index 560500b8..90692e84 100644 --- a/src/nemos/fetch/fetch_data.py +++ b/src/nemos/fetch/fetch_data.py @@ -15,7 +15,7 @@ try: import pooch from pooch import Pooch - from tqdm.auto import tqdm + from tqdm.autonotebook import tqdm except ImportError: pooch = None Pooch = None @@ -127,7 +127,7 @@ def fetch_data( ) retriever = _create_retriever(path) # Fetch the dataset using pooch. - return retriever.fetch(dataset_name, progressbar=tqdm) + return retriever.fetch(dataset_name) def download_dandi_data(dandiset_id: str, filepath: str) -> NWBHDF5IO: From 9448c23594c8453cbac6572546f416160abbe714 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 22 Nov 2024 11:36:45 -0500 Subject: [PATCH 091/107] fix refs --- docs/background/plot_00_conceptual_intro.md | 13 ++++++++----- docs/background/plot_02_ND_basis_function.md | 4 ++-- docs/background/plot_03_1D_convolution.md | 2 +- docs/how_to_guide/plot_02_glm_demo.md | 14 ++++++++------ docs/how_to_guide/plot_03_population_glm.md | 1 + docs/quickstart.md | 14 +++++++------- docs/tutorials/plot_01_current_injection.md | 4 ++-- 7 files changed, 29 insertions(+), 23 deletions(-) diff --git a/docs/background/plot_00_conceptual_intro.md b/docs/background/plot_00_conceptual_intro.md index 686d7903..3f28faaa 100644 --- a/docs/background/plot_00_conceptual_intro.md +++ b/docs/background/plot_00_conceptual_intro.md @@ -186,7 +186,7 @@ fig = doc_plots.lnp_schematic(input_feature, weights, intercepts, plot_nonlinear=True) ``` -:::{info} +:::{note} In NeMoS, the non-linearity is kept fixed. We default to the exponential, but a small number of other choices, such as soft-plus, are allowed. The allowed choices guarantee both the non-negativity constraint described @@ -196,7 +196,10 @@ is not guaranteed in general. ::: Specifically, our firing rate is: -$$ \lambda (t) = \exp (L(x(t)) = \exp (w x(t) + c) \tag{2}$$ + +$$ +\lambda (t) = \exp (L(x(t)) = \exp (w x(t) + c) \tag{2} +$$ We can see that the output of the nonlinear transformation is always positive, though note that the y-values have changed drastically. @@ -236,7 +239,7 @@ $$ \sum\_t \log P(y(t) | \lambda(t)) \propto \sum\_t y(t) \log(\lambda(t)) - This is the objective function of the GLM model: we are trying to find the firing rate that maximizes the likelihood of the observed spike train. -:::{info} +:::{note} **In NeMoS, the log-likelihood can be computed directly by calling the `score` method, passing the predictors and the counts. The method first @@ -251,5 +254,5 @@ computes the rate $\lambda(t)$ using (2) and then the likelihood using So far, we have focused on the relatively simple LNP model of spike generation, which is a special case of a GLM. The LNP model has some known shortcomings[$^{[1]}$](#ref-1). For instance, LNP ignores things like refactory periods and other history-dependent features of spiking in a neuron. As we will show in other demos, such _spike history filters_ can be built into GLMs to give more accurate results. We will also show how, if you have recordings from a large _population_ of neurons simultaneously, you can build connections between the neurons into the GLM in the form of _coupling filters_. This can help answer the degree to which activity is driven primarily by the input X, or by network influences in the population. ## References - -[1] Pillow, JW, Shlens, J, Paninski, L, Sher, A, Litke, AM, Chichilnisky, EJ, Simoncelli, EP (2008), "Spatio-temporal correlations and visual signalling in a complete neuronal population." Nature 454: 995-9. +(ref-1)= +[1] [Pillow, JW, Shlens, J, Paninski, L, Sher, A, Litke, AM, Chichilnisky, EJ, Simoncelli, EP (2008), "Spatio-temporal correlations and visual signalling in a complete neuronal population." Nature 454: 995-9.](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2684455/) diff --git a/docs/background/plot_02_ND_basis_function.md b/docs/background/plot_02_ND_basis_function.md index 23338951..ef03a0cb 100644 --- a/docs/background/plot_02_ND_basis_function.md +++ b/docs/background/plot_02_ND_basis_function.md @@ -315,7 +315,7 @@ if path.exists(): fig.savefig(path / "plot_02_ND_basis_function.svg") ``` -:::{info} +:::{note} Basis objects of different types can be combined through multiplication or addition. This feature is particularly useful when one of the axes represents a periodic variable and another is non-periodic. A practical example would be characterizing the responses to position @@ -383,7 +383,7 @@ plt.show() print(f"Sparsity check: {(Z == 0).sum() / Z.size * 100: .2f}% of the evaluated basis is null.") ``` -:::{info} +:::{note} The evaluated basis is going to be **sparse** if the basis elements support do not cover the full domain of the basis. ::: diff --git a/docs/background/plot_03_1D_convolution.md b/docs/background/plot_03_1D_convolution.md index bbf1a8a7..663da6e8 100644 --- a/docs/background/plot_03_1D_convolution.md +++ b/docs/background/plot_03_1D_convolution.md @@ -72,7 +72,7 @@ spk[-4] = 1 Generate and plot a filter, then execute a convolution in "valid" mode for all trials and neurons. In nemos, you can use the [`tensor_convolve`](nemos.convolve.tensor_convolve) function for this. -:::{info} +:::{note} The `"valid"` mode of convolution only calculates the product when the two input vectors overlap completely, avoiding border artifacts. The outcome of such a convolution will be an array of `max(M,N) - min(M,N) + 1` elements in length, where `M` and `N` represent the number diff --git a/docs/how_to_guide/plot_02_glm_demo.md b/docs/how_to_guide/plot_02_glm_demo.md index 83c400a9..840a636c 100644 --- a/docs/how_to_guide/plot_02_glm_demo.md +++ b/docs/how_to_guide/plot_02_glm_demo.md @@ -278,12 +278,13 @@ plt.eventplot(np.where(spikes)[0]) In this section, we will show you how to generate spikes from a population; We assume that the coupling filters are known or inferred. -!!! warning - Making sure that the dynamics of your recurrent neural network are stable is non-trivial[$^{[1]}$](#ref-1). In particular, - coupling weights obtained by fitting a GLM by maximum-likelihood can generate unstable dynamics. If the - dynamics of your recurrently coupled model are unstable, you can try a `soft-plus` non-linearity - instead of an exponential, and you can "shrink" your weights until stability is reached. +:::{warning} +Making sure that the dynamics of your recurrent neural network are stable is non-trivial[$^{[1]}$](#ref-1). In particular, +coupling weights obtained by fitting a GLM by maximum-likelihood can generate unstable dynamics. If the +dynamics of your recurrently coupled model are unstable, you can try a `soft-plus` non-linearity +instead of an exponential, and you can "shrink" your weights until stability is reached. +::: ```{code-cell} ipython3 @@ -458,4 +459,5 @@ if path.exists(): ## References -[1] Arribas, Diego, Yuan Zhao, and Il Memming Park. "Rescuing neural spike train models from bad MLE." Advances in Neural Information Processing Systems 33 (2020): 2293-2303. +(ref-1)= +[1] [Arribas, Diego, Yuan Zhao, and Il Memming Park. "Rescuing neural spike train models from bad MLE." Advances in Neural Information Processing Systems 33 (2020): 2293-2303.](https://arxiv.org/abs/2010.12362) \ No newline at end of file diff --git a/docs/how_to_guide/plot_03_population_glm.md b/docs/how_to_guide/plot_03_population_glm.md index 611c43a9..316d058a 100644 --- a/docs/how_to_guide/plot_03_population_glm.md +++ b/docs/how_to_guide/plot_03_population_glm.md @@ -103,6 +103,7 @@ model.fit(X, spikes) print(f"population GLM log-likelihood: {model.score(X, spikes)}") ``` +(neuron-specific-features)= ## Neuron-specific features If you want to model neurons with different input features, the way to do so is to specify a `feature_mask`. Let's assume that we have two neurons, share one shared input, and have an extra private one, for a total of diff --git a/docs/quickstart.md b/docs/quickstart.md index 72b69536..062bdb25 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -284,7 +284,7 @@ You can specify the regularization scheme and its strength when initializing the ## **Pre-processing with `pynapple`** -:::{info} +:::{note} This section assumes some familiarity with the `pynapple` package for time series manipulation and data exploration. If you'd like to learn more about it, take a look at the [`pynapple` documentation](https://pynapple-org.github.io/pynapple/). @@ -301,7 +301,7 @@ also be a `pynapple` time series. A canonical example of this behavior is the `predict` method of `GLM`. -```python +```ipython >>> import numpy as np >>> import pynapple as nap @@ -331,7 +331,7 @@ Let's see how you can greatly streamline your analysis pipeline by integrating ` You can download this dataset by clicking [here](https://www.dropbox.com/s/su4oaje57g3kit9/A2929-200711.zip?dl=1). ::: -```python +```ipython >>> import nemos as nmo >>> import pynapple as nap @@ -361,7 +361,7 @@ You can download this dataset by clicking [here](https://www.dropbox.com/s/su4oa Finally, let's compare the tuning curves -```python +```ipython >>> import numpy as np >>> import matplotlib.pyplot as plt @@ -400,7 +400,7 @@ For example, if we would like to tune the critical hyper-parameter `regularizer_ [^1]: For a detailed explanation and practical examples, refer to the [cross-validation page](https://scikit-learn.org/stable/modules/cross_validation.html) in the `scikit-learn` documentation. -```python +```ipython >>> # set up the model >>> import nemos as nmo @@ -416,7 +416,7 @@ For example, if we would like to tune the critical hyper-parameter `regularizer_ Fit a 5-fold cross-validation scheme for comparing two different regularizer strengths: -```python +```ipython >>> from sklearn.model_selection import GridSearchCV @@ -440,7 +440,7 @@ For more information and a practical example on how to construct a parameter gri Finally, we can print the regularizer strength with the best cross-validated performance: -```python +```ipython >>> # print best regularizer strength >>> print(cls.best_params_) diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md index bfc81e4d..9662ab6e 100644 --- a/docs/tutorials/plot_01_current_injection.md +++ b/docs/tutorials/plot_01_current_injection.md @@ -294,7 +294,7 @@ plotted together. One common way to visualize a rough estimate of firing rate is to smooth the spikes by convolving them with a Gaussian filter. -:::{info} +:::{note} This is a heuristic for getting the firing rate, and shouldn't be taken as the literal truth (to see why, pass a firing rate through a Poisson @@ -734,7 +734,7 @@ the same dataset, whether that's models using different regularizers and solvers or those using different predictors, comparing log-likelihoods is a reasonable thing to do. -:::{info} +:::{note} Under the hood, NeMoS is minimizing the negative log-likelihood, as is typical in many optimization contexts. [`score`](nemos.glm.GLM.score) returns the real From 52cc109e6cb119ec747cc07e36d1942f65981c83 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 22 Nov 2024 11:39:17 -0500 Subject: [PATCH 092/107] removed bold from note --- docs/background/plot_00_conceptual_intro.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/background/plot_00_conceptual_intro.md b/docs/background/plot_00_conceptual_intro.md index 3f28faaa..afd6c08c 100644 --- a/docs/background/plot_00_conceptual_intro.md +++ b/docs/background/plot_00_conceptual_intro.md @@ -241,10 +241,10 @@ firing rate that maximizes the likelihood of the observed spike train. :::{note} -**In NeMoS, the log-likelihood can be computed directly by calling the +In NeMoS, the log-likelihood can be computed directly by calling the `score` method, passing the predictors and the counts. The method first computes the rate $\lambda(t)$ using (2) and then the likelihood using -(4).** This method is used under the hood during optimization. +(4). This method is used under the hood during optimization. ::: From 43ec609b6e10e29fe1b5ed5041225da9364f990c Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 22 Nov 2024 12:10:02 -0500 Subject: [PATCH 093/107] fixed alt --- docs/background/plot_01_1D_basis_function.md | 2 +- docs/background/plot_02_ND_basis_function.md | 2 +- docs/background/plot_03_1D_convolution.md | 2 +- docs/how_to_guide/README.md | 10 +++++----- docs/how_to_guide/plot_02_glm_demo.md | 2 +- docs/how_to_guide/plot_03_population_glm.md | 2 +- docs/how_to_guide/plot_04_batch_glm.md | 2 +- docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md | 2 +- docs/how_to_guide/plot_06_glm_pytree.md | 2 +- docs/tutorials/plot_01_current_injection.md | 2 +- docs/tutorials/plot_02_head_direction.md | 2 +- docs/tutorials/plot_03_grid_cells.md | 2 +- docs/tutorials/plot_04_v1_cells.md | 2 +- docs/tutorials/plot_05_place_cells.md | 2 +- docs/tutorials/plot_06_calcium_imaging.md | 2 +- 15 files changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/background/plot_01_1D_basis_function.md b/docs/background/plot_01_1D_basis_function.md index 4b70cd8f..3e69e301 100644 --- a/docs/background/plot_01_1D_basis_function.md +++ b/docs/background/plot_01_1D_basis_function.md @@ -104,7 +104,7 @@ else: path = Path("../_build/html/_static/thumbnails/background") # make sure the folder exists if run from build -if root or Path("../_build/html/_static/thumbnails").exists(): +if root or Path("../_build/html/_static").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/background/plot_02_ND_basis_function.md b/docs/background/plot_02_ND_basis_function.md index ef03a0cb..c14c0ba4 100644 --- a/docs/background/plot_02_ND_basis_function.md +++ b/docs/background/plot_02_ND_basis_function.md @@ -308,7 +308,7 @@ else: path = Path("../_build/html/_static/thumbnails/background") # make sure the folder exists if run from build -if root or Path("../_build/html/_static/thumbnails").exists(): +if root or Path("../_build/html/_static").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/background/plot_03_1D_convolution.md b/docs/background/plot_03_1D_convolution.md index 663da6e8..fa7335e5 100644 --- a/docs/background/plot_03_1D_convolution.md +++ b/docs/background/plot_03_1D_convolution.md @@ -179,7 +179,7 @@ else: path = Path("../_build/html/_static/thumbnails/background") # make sure the folder exists if run from build -if root or Path("../_build/html/_static/thumbnails").exists(): +if root or Path("../_build/html/_static").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/how_to_guide/README.md b/docs/how_to_guide/README.md index af6107b6..1a3ec6c8 100644 --- a/docs/how_to_guide/README.md +++ b/docs/how_to_guide/README.md @@ -19,7 +19,7 @@ pip install nemos[examples] :::{grid-item-card}
-Place cells. +GLM demo.
```{toctree} @@ -32,7 +32,7 @@ plot_02_glm_demo.md :::{grid-item-card}
-Place cells. +Population GLM.
```{toctree} @@ -45,7 +45,7 @@ plot_03_population_glm.md :::{grid-item-card}
-Place cells. +Batched GLM.
```{toctree} @@ -58,7 +58,7 @@ plot_04_batch_glm.md :::{grid-item-card}
-Place cells. +Pipelining and cross-validation.
```{toctree} @@ -71,7 +71,7 @@ plot_05_sklearn_pipeline_cv_demo.md :::{grid-item-card}
-Place cells. +PyTrees.
```{toctree} diff --git a/docs/how_to_guide/plot_02_glm_demo.md b/docs/how_to_guide/plot_02_glm_demo.md index 840a636c..fe18d3ec 100644 --- a/docs/how_to_guide/plot_02_glm_demo.md +++ b/docs/how_to_guide/plot_02_glm_demo.md @@ -450,7 +450,7 @@ else: path = Path("../_build/html/_static/thumbnails/how_to_guide") # make sure the folder exists if run from build -if root or Path("../_build/html/_static/thumbnails").exists(): +if root or Path("../_build/html/_static").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/how_to_guide/plot_03_population_glm.md b/docs/how_to_guide/plot_03_population_glm.md index 316d058a..7c27acd5 100644 --- a/docs/how_to_guide/plot_03_population_glm.md +++ b/docs/how_to_guide/plot_03_population_glm.md @@ -231,7 +231,7 @@ else: path = Path("../_build/html/_static/thumbnails/how_to_guide") # make sure the folder exists if run from build -if root or Path("../_build/html/_static/thumbnails").exists(): +if root or Path("../_build/html/_static").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/how_to_guide/plot_04_batch_glm.md b/docs/how_to_guide/plot_04_batch_glm.md index 5de99c1f..707e90da 100644 --- a/docs/how_to_guide/plot_04_batch_glm.md +++ b/docs/how_to_guide/plot_04_batch_glm.md @@ -208,7 +208,7 @@ else: path = Path("../_build/html/_static/thumbnails/how_to_guide") # make sure the folder exists if run from build -if root or Path("../_build/html/_static/thumbnails").exists(): +if root or Path("../_build/html/_static").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md index 6072582c..92c385a9 100644 --- a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md +++ b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md @@ -431,7 +431,7 @@ else: path = Path("../_build/html/_static/thumbnails/how_to_guide") # make sure the folder exists if run from build -if root or Path("../_build/html/_static/thumbnails").exists(): +if root or Path("../_build/html/_static").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/how_to_guide/plot_06_glm_pytree.md b/docs/how_to_guide/plot_06_glm_pytree.md index 7110fb59..6945460e 100644 --- a/docs/how_to_guide/plot_06_glm_pytree.md +++ b/docs/how_to_guide/plot_06_glm_pytree.md @@ -261,7 +261,7 @@ else: path = Path("../_build/html/_static/thumbnails/how_to_guide") # make sure the folder exists if run from build -if root or Path("../_build/html/_static/thumbnails").exists(): +if root or Path("../_build/html/_static").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md index 9662ab6e..9d0402b7 100644 --- a/docs/tutorials/plot_01_current_injection.md +++ b/docs/tutorials/plot_01_current_injection.md @@ -633,7 +633,7 @@ else: path = Path("../_build/html/_static/thumbnails/tutorials") # make sure the folder exists if run from build -if root or Path("../_build/html/_static/thumbnails").exists(): +if root or Path("../_build/html/_static").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/tutorials/plot_02_head_direction.md b/docs/tutorials/plot_02_head_direction.md index 9cf9d992..0618b188 100644 --- a/docs/tutorials/plot_02_head_direction.md +++ b/docs/tutorials/plot_02_head_direction.md @@ -715,7 +715,7 @@ else: path = Path("../_build/html/_static/thumbnails/tutorials") # make sure the folder exists if run from build -if root or Path("../_build/html/_static/thumbnails").exists(): +if root or Path("../_build/html/_static").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/tutorials/plot_03_grid_cells.md b/docs/tutorials/plot_03_grid_cells.md index c3149a22..f4977cbd 100644 --- a/docs/tutorials/plot_03_grid_cells.md +++ b/docs/tutorials/plot_03_grid_cells.md @@ -344,7 +344,7 @@ else: path = Path("../_build/html/_static/thumbnails/tutorials") # make sure the folder exists if run from build -if root or Path("../_build/html/_static/thumbnails").exists(): +if root or Path("../_build/html/_static").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/tutorials/plot_04_v1_cells.md b/docs/tutorials/plot_04_v1_cells.md index e3d38bf6..bd91d5ef 100644 --- a/docs/tutorials/plot_04_v1_cells.md +++ b/docs/tutorials/plot_04_v1_cells.md @@ -247,7 +247,7 @@ else: path = Path("../_build/html/_static/thumbnails/tutorials") # make sure the folder exists if run from build -if root or Path("../_build/html/_static/thumbnails").exists(): +if root or Path("../_build/html/_static").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/tutorials/plot_05_place_cells.md b/docs/tutorials/plot_05_place_cells.md index 9a57f36e..82256887 100644 --- a/docs/tutorials/plot_05_place_cells.md +++ b/docs/tutorials/plot_05_place_cells.md @@ -159,7 +159,7 @@ else: path = Path("../_build/html/_static/thumbnails/tutorials") # make sure the folder exists if run from build -if root or Path("../_build/html/_static/thumbnails").exists(): +if root or Path("../_build/html/_static").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): diff --git a/docs/tutorials/plot_06_calcium_imaging.md b/docs/tutorials/plot_06_calcium_imaging.md index 2b289b55..1dbfc46e 100644 --- a/docs/tutorials/plot_06_calcium_imaging.md +++ b/docs/tutorials/plot_06_calcium_imaging.md @@ -371,7 +371,7 @@ else: path = Path("../_build/html/_static/thumbnails/tutorials") # make sure the folder exists if run from build -if root or Path("../_build/html/_static/thumbnails").exists(): +if root or Path("../_build/html/_static").exists(): path.mkdir(parents=True, exist_ok=True) if path.exists(): From f9dad13e7026adfbaa8b4561125879370479169a Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 22 Nov 2024 12:17:23 -0500 Subject: [PATCH 094/107] fixed admonitions --- .../plot_05_sklearn_pipeline_cv_demo.md | 34 +++++++++---------- docs/tutorials/plot_01_current_injection.md | 17 +++++----- docs/tutorials/plot_02_head_direction.md | 11 +++--- 3 files changed, 32 insertions(+), 30 deletions(-) diff --git a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md index 92c385a9..c72c1037 100644 --- a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md +++ b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md @@ -530,24 +530,24 @@ The plot confirms that the firing rate distribution is accurately captured by ou -!!! warning - Please note that because it would lead to unexpected behavior, mixing the two ways of defining values for the parameter grid is not allowed. The following would lead to an error: - - ```python - param_grid = dict( - glm__regularizer_strength=(0.1, 0.01, 0.001, 1e-6), - transformerbasis__n_basis_funcs=(3, 5, 10, 20, 100), - transformerbasis___basis=( - nmo.basis.RaisedCosineBasisLinear(5), - nmo.basis.RaisedCosineBasisLinear(10), - nmo.basis.RaisedCosineBasisLog(5), - nmo.basis.RaisedCosineBasisLog(10), - nmo.basis.MSplineBasis(5), - nmo.basis.MSplineBasis(10), - ), - ) - ``` +:::{warning} +Please note that because it would lead to unexpected behavior, mixing the two ways of defining values for the parameter grid is not allowed. The following would lead to an error: +```python +param_grid = dict( + glm__regularizer_strength=(0.1, 0.01, 0.001, 1e-6), + transformerbasis__n_basis_funcs=(3, 5, 10, 20, 100), + transformerbasis___basis=( + nmo.basis.RaisedCosineBasisLinear(5), + nmo.basis.RaisedCosineBasisLinear(10), + nmo.basis.RaisedCosineBasisLog(5), + nmo.basis.RaisedCosineBasisLog(10), + nmo.basis.MSplineBasis(5), + nmo.basis.MSplineBasis(10), + ), +) +``` +::: diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md index 9d0402b7..dfd163f2 100644 --- a/docs/tutorials/plot_01_current_injection.md +++ b/docs/tutorials/plot_01_current_injection.md @@ -349,13 +349,12 @@ print(type(firing_rate)) Now that we've done all this preparation, let's make a plot to more easily visualize the data. -!!! note - - We're hiding the details of the plotting function for the purposes of this - tutorial, but you can find it in [the source - code](https://github.com/flatironinstitute/nemos/blob/development/src/nemos/_documentation_utils/plotting.py) - if you are interested. +:::{note} +We're hiding the details of the plotting function for the purposes of this tutorial, but you can find it in [the source +code](https://github.com/flatironinstitute/nemos/blob/development/src/nemos/_documentation_utils/plotting.py) +if you are interested. +::: ```{code-cell} ipython3 doc_plots.current_injection_plot(current, spikes, firing_rate) @@ -388,9 +387,11 @@ Pynapple can compute a tuning curve to help us answer this question, by binning our spikes based on the instantaneous input current and computing the firing rate within those bins: -!!! note "Tuning curve in `pynapple`" - [`compute_1d_tuning_curves`](https://pynapple.org/generated/pynapple.process.tuning_curves.html#pynapple.process.tuning_curves.compute_1d_tuning_curves) : compute the firing rate as a function of a 1-dimensional feature. +:::{admonition} Tuning curve in `pynapple` +:class: note +[`compute_1d_tuning_curves`](https://pynapple.org/generated/pynapple.process.tuning_curves.html#pynapple.process.tuning_curves.compute_1d_tuning_curves) : compute the firing rate as a function of a 1-dimensional feature. +::: ```{code-cell} ipython3 tuning_curve = nap.compute_1d_tuning_curves(spikes, current, nb_bins=15) diff --git a/docs/tutorials/plot_02_head_direction.md b/docs/tutorials/plot_02_head_direction.md index 0618b188..cf408662 100644 --- a/docs/tutorials/plot_02_head_direction.md +++ b/docs/tutorials/plot_02_head_direction.md @@ -399,12 +399,13 @@ whereas whether an input happened 51 or 55 msec ago is less important. doc_plots.plot_basis(); ``` -!!! info +:::{note} - We provide a handful of different choices for basis functions, and - selecting the proper basis function for your input is an important - analytical step. We will eventually provide guidance on this choice, but - for now we'll give you a decent choice. +We provide a handful of different choices for basis functions, and +selecting the proper basis function for your input is an important +analytical step. We will eventually provide guidance on this choice, but +for now we'll give you a decent choice. +::: NeMoS includes [`Basis`](nemos_basis) objects to handle the construction and use of these basis functions. From daf7989e4643aef9b4260f632bebef07e179f622 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 22 Nov 2024 12:24:55 -0500 Subject: [PATCH 095/107] import tqdm.auto directly --- docs/tutorials/plot_01_current_injection.md | 1 + src/nemos/fetch/fetch_data.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md index dfd163f2..d52119be 100644 --- a/docs/tutorials/plot_01_current_injection.md +++ b/docs/tutorials/plot_01_current_injection.md @@ -625,6 +625,7 @@ fig = doc_plots.current_injection_plot(current, spikes, firing_rate, # save image for thumbnail import os +from pathlib import Path root = os.environ.get("READTHEDOCS_OUTPUT") if root: diff --git a/src/nemos/fetch/fetch_data.py b/src/nemos/fetch/fetch_data.py index 90692e84..652a15bd 100644 --- a/src/nemos/fetch/fetch_data.py +++ b/src/nemos/fetch/fetch_data.py @@ -15,7 +15,7 @@ try: import pooch from pooch import Pooch - from tqdm.autonotebook import tqdm + from tqdm.auto import tqdm except ImportError: pooch = None Pooch = None From d326019959c65004b7a30772c16b6101bb265d77 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 22 Nov 2024 15:20:21 -0500 Subject: [PATCH 096/107] some linting of the docstrings --- docs/_templates/autosummary/class.rst | 21 ++++++++------- docs/conf.py | 8 ++++++ src/nemos/basis.py | 39 ++++++++++++++------------- src/nemos/convolve.py | 20 ++++++++------ src/nemos/glm.py | 4 +-- src/nemos/observation_models.py | 2 +- src/nemos/typing.py | 2 +- 7 files changed, 56 insertions(+), 40 deletions(-) diff --git a/docs/_templates/autosummary/class.rst b/docs/_templates/autosummary/class.rst index 0d066e33..068175b2 100644 --- a/docs/_templates/autosummary/class.rst +++ b/docs/_templates/autosummary/class.rst @@ -6,28 +6,29 @@ :members: :inherited-members: -{% block methods %} - .. automethod:: __init__ - - {% if methods %} - .. rubric:: Methods +{% block attributes %} + {% if attributes %} + .. rubric:: Attributes .. autosummary:: :toctree: ./ - {% for item in methods %} + {% for item in attributes %} ~{{ objname }}.{{ item }} {%- endfor %} {% endif %} {% endblock %} -{% block attributes %} - {% if attributes %} - .. rubric:: Attributes +{% block methods %} + .. automethod:: __init__ + + {% if methods %} + .. rubric:: Methods .. autosummary:: :toctree: ./ - {% for item in attributes %} + {% for item in methods %} ~{{ objname }}.{{ item }} {%- endfor %} {% endif %} {% endblock %} + diff --git a/docs/conf.py b/docs/conf.py index 96ee47c9..5a5b2c43 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -68,6 +68,7 @@ 'inherited-members': True, 'undoc-members': True, 'show-inheritance': True, + 'special-members': '__call__, __add__, __mul__, __pow__' } # # napolean configs @@ -90,6 +91,7 @@ "TsdFrame": "pynapple.TsdFrame", "JaxArray": "JaxArray", } +autodoc_typehints_format = "short" numfig = True @@ -150,3 +152,9 @@ nb_execution_timeout = 60 * 15 # Set timeout in seconds (e.g., 15 minutes) nitpicky = True + +# Get exclusion patterns from an environment variable +exclude_tutorials = os.environ.get("EXCLUDE_TUTORIALS", "false").lower() == "true" + +if exclude_tutorials: + nb_execution_excludepatterns = ["tutorials/**", "how_to_guide/**", "background/**"] \ No newline at end of file diff --git a/src/nemos/basis.py b/src/nemos/basis.py index d572c502..0b6eee9b 100644 --- a/src/nemos/basis.py +++ b/src/nemos/basis.py @@ -503,7 +503,7 @@ class Basis(Base, abc.ABC): The label of the basis, intended to be descriptive of the task variable being processed. For example: velocity, position, spike_counts. **kwargs : - Additional keyword arguments passed to ``nemos.convolve.create_convolutional_predictor`` when + Additional keyword arguments passed to :func:`nemos.convolve.create_convolutional_predictor` when ``mode='conv'``; These arguments are used to change the default behavior of the convolution. For example, changing the ``predictor_causality``, which by default is set to ``"causal"``. Note that one cannot change the default value for the ``axis`` parameter. Basis assumes @@ -512,11 +512,14 @@ class Basis(Base, abc.ABC): Raises ------ ValueError: - - If ``mode`` is not 'eval' or 'conv'. - - If ``kwargs`` are not None and ``mode =="eval"``. - - If ``kwargs`` include parameters not recognized or do not have + If ``mode`` is not 'eval' or 'conv'. + ValueError: + If ``kwargs`` are not None and ``mode =="eval"``. + ValueError: + If ``kwargs`` include parameters not recognized or do not have default values in ``create_convolutional_predictor``. - - If ``axis`` different from 0 is provided as a keyword argument (samples must always be in the first axis). + ValueError: + If ``axis`` different from 0 is provided as a keyword argument (samples must always be in the first axis). """ def __init__( @@ -1151,7 +1154,7 @@ def __pow__(self, exponent: int) -> MultiplicativeBasis: Returns ------- : - The product of the basis with itself "exponent" times. Equivalent to self * self * ... * self. + The product of the basis with itself "exponent" times. Equivalent to ``self * self * ... * self``. Raises ------ @@ -1326,11 +1329,11 @@ def split_by_feature( **How it works:** - If the basis expects an input shape ``(n_samples, n_inputs)``, then the feature axis length will - be ``total_n_features = n_inputs * n_basis_funcs``. This axis is reshaped into dimensions - ``(n_inputs, n_basis_funcs)``. + be ``total_n_features = n_inputs * n_basis_funcs``. This axis is reshaped into dimensions + ``(n_inputs, n_basis_funcs)``. - If the basis expects an input of shape ``(n_samples,)``, then the feature axis length will - be ``total_n_features = n_basis_funcs``. This axis is reshaped into ``(1, n_basis_funcs)``. + be ``total_n_features = n_basis_funcs``. This axis is reshaped into ``(1, n_basis_funcs)``. For example, if the input array ``x`` has shape ``(1, 2, total_n_features, 4, 5)``, then after applying this method, it will be reshaped into ``(1, 2, n_inputs, n_basis_funcs, 4, 5)``. @@ -1924,7 +1927,7 @@ class SplineBasis(Basis, abc.ABC): The label of the basis, intended to be descriptive of the task variable being processed. For example: velocity, position, spike_counts. **kwargs : - Additional keyword arguments passed to ``nemos.convolve.create_convolutional_predictor`` when + Additional keyword arguments passed to :func:`nemos.convolve.create_convolutional_predictor` when ``mode='conv'``; These arguments are used to change the default behavior of the convolution. For example, changing the ``predictor_causality``, which by default is set to ``"causal"``. Note that one cannot change the default value for the ``axis`` parameter. Basis assumes @@ -2090,7 +2093,7 @@ class MSplineBasis(SplineBasis): The label of the basis, intended to be descriptive of the task variable being processed. For example: velocity, position, spike_counts. **kwargs: - Additional keyword arguments passed to ``nemos.convolve.create_convolutional_predictor`` when + Additional keyword arguments passed to :func:`nemos.convolve.create_convolutional_predictor` when ``mode='conv'``; These arguments are used to change the default behavior of the convolution. For example, changing the ``predictor_causality``, which by default is set to ``"causal"``. Note that one cannot change the default value for the ``axis`` parameter. Basis assumes @@ -2256,7 +2259,7 @@ class BSplineBasis(SplineBasis): The label of the basis, intended to be descriptive of the task variable being processed. For example: velocity, position, spike_counts. **kwargs : - Additional keyword arguments passed to ``nemos.convolve.create_convolutional_predictor`` when + Additional keyword arguments passed to :func:`nemos.convolve.create_convolutional_predictor` when ``mode='conv'``; These arguments are used to change the default behavior of the convolution. For example, changing the ``predictor_causality``, which by default is set to ``"causal"``. Note that one cannot change the default value for the ``axis`` parameter. Basis assumes @@ -2395,7 +2398,7 @@ class CyclicBSplineBasis(SplineBasis): The label of the basis, intended to be descriptive of the task variable being processed. For example: velocity, position, spike_counts. **kwargs : - Additional keyword arguments passed to ``nemos.convolve.create_convolutional_predictor`` when + Additional keyword arguments passed to :func:`nemos.convolve.create_convolutional_predictor` when ``mode='conv'``; These arguments are used to change the default behavior of the convolution. For example, changing the ``predictor_causality``, which by default is set to ``"causal"``. Note that one cannot change the default value for the ``axis`` parameter. Basis assumes @@ -2559,7 +2562,7 @@ class RaisedCosineBasisLinear(Basis): The label of the basis, intended to be descriptive of the task variable being processed. For example: velocity, position, spike_counts. **kwargs : - Additional keyword arguments passed to ``nemos.convolve.create_convolutional_predictor`` when + Additional keyword arguments passed to :func:`nemos.convolve.create_convolutional_predictor` when ``mode='conv'``; These arguments are used to change the default behavior of the convolution. For example, changing the ``predictor_causality``, which by default is set to ``"causal"``. Note that one cannot change the default value for the ``axis`` parameter. Basis assumes @@ -2774,7 +2777,7 @@ class RaisedCosineBasisLog(RaisedCosineBasisLinear): The label of the basis, intended to be descriptive of the task variable being processed. For example: velocity, position, spike_counts. **kwargs : - Additional keyword arguments passed to ``nemos.convolve.create_convolutional_predictor`` when + Additional keyword arguments passed to :func:`nemos.convolve.create_convolutional_predictor` when ``mode='conv'``; These arguments are used to change the default behavior of the convolution. For example, changing the ``predictor_causality``, which by default is set to ``"causal"``. Note that one cannot change the default value for the ``axis`` parameter. Basis assumes @@ -2945,7 +2948,7 @@ class OrthExponentialBasis(Basis): The label of the basis, intended to be descriptive of the task variable being processed. For example: velocity, position, spike_counts. **kwargs : - Additional keyword arguments passed to ``nemos.convolve.create_convolutional_predictor`` when + Additional keyword arguments passed to :func:`nemos.convolve.create_convolutional_predictor` when ``mode='conv'``; These arguments are used to change the default behavior of the convolution. For example, changing the ``predictor_causality``, which by default is set to ``"causal"``. Note that one cannot change the default value for the ``axis`` parameter. Basis assumes @@ -2988,9 +2991,9 @@ def __init__( @property def decay_rates(self): - """Decay rate. + r"""Decay rate. - The rate of decay of the exponential functions. If :math:`f_i(t) = \exp{-\alpha_i t}` is the i-th decay + The rate of decay of the exponential functions. If :math:`f_i(t) = e^{-\alpha_i t}` is the i-th decay exponential before orthogonalization, :math:`\alpha_i` is the i-th element of the ``decay_rate`` vector. """ return self._decay_rates diff --git a/src/nemos/convolve.py b/src/nemos/convolve.py index faddac39..248305c7 100644 --- a/src/nemos/convolve.py +++ b/src/nemos/convolve.py @@ -248,14 +248,18 @@ def create_convolutional_predictor( Raises ------ - ValueError - - If `basis_matrix` is not a 2-dimensional array or has a singleton first dimension. - - If `time_series` does not contain arrays of at least one dimension or contains - arrays with a dimensionality less than `axis`. - - If any array within `time_series` or `basis_matrix` is empty. - - If the number of elements along the convolution axis in any array within `time_series` - is less than the window size of the `basis_matrix`. - - If shifting is attempted with 'acausal' causality. + ValueError: + If `basis_matrix` is not a 2-dimensional array or has a singleton first dimension. + ValueError: + If `time_series` does not contain arrays of at least one dimension or contains + arrays with a dimensionality less than `axis`. + ValueError: + If any array within `time_series` or `basis_matrix` is empty. + ValueError: + If the number of elements along the convolution axis in any array within `time_series` + is less than the window size of the `basis_matrix`. + ValueError: + If shifting is attempted with 'acausal' causality. """ # convert to jnp.ndarray basis_matrix = jnp.asarray(basis_matrix) diff --git a/src/nemos/glm.py b/src/nemos/glm.py index 95817089..d348028f 100644 --- a/src/nemos/glm.py +++ b/src/nemos/glm.py @@ -1534,10 +1534,10 @@ def fit( an NDArray or a :class:`nemos.pytrees.FeaturePytree` of 0s and 1s. In particular, - If the mask is in array format, feature ``i`` is a predictor for neuron ``j`` if - ``feature_mask[i, j] == 1``. + ``feature_mask[i, j] == 1``. - If the mask is a :class:``nemos.pytrees.FeaturePytree``, then - ``"feature_name"`` is a predictor of neuron ``j`` if ``feature_mask["feature_name"][j] == 1``. + ``"feature_name"`` is a predictor of neuron ``j`` if ``feature_mask["feature_name"][j] == 1``. Examples -------- diff --git a/src/nemos/observation_models.py b/src/nemos/observation_models.py index f84dfb96..e4bc407c 100644 --- a/src/nemos/observation_models.py +++ b/src/nemos/observation_models.py @@ -24,7 +24,7 @@ class Observations(Base, abc.ABC): This is an abstract base class used to implement observation models for neural data. Specific observation models that inherit from this class should define their versions of the abstract methods such as :meth:`~nemos.observation_models.Observations.log_likelihood`, - :meth`~nemos.observation_models.Observations.sample_generator`, and + :meth:`~nemos.observation_models.Observations.sample_generator`, and :meth:`~nemos.observation_models.Observations.deviance`. Attributes diff --git a/src/nemos/typing.py b/src/nemos/typing.py index dd9bc5a6..f1cfc4fc 100644 --- a/src/nemos/typing.py +++ b/src/nemos/typing.py @@ -4,7 +4,7 @@ import jax.numpy as jnp import jaxopt -from jax._src.typing import ArrayLike +from jax.typing import ArrayLike from .pytrees import FeaturePytree From 67b869222c8cfe4ebbbb16f2ea37ecc7c5fb2dd8 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 22 Nov 2024 15:21:03 -0500 Subject: [PATCH 097/107] linted --- src/nemos/fetch/fetch_data.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/nemos/fetch/fetch_data.py b/src/nemos/fetch/fetch_data.py index 652a15bd..faf43f59 100644 --- a/src/nemos/fetch/fetch_data.py +++ b/src/nemos/fetch/fetch_data.py @@ -11,7 +11,6 @@ import pathlib from typing import Optional, Union - try: import pooch from pooch import Pooch From 1aaddcf3c10b35742911bb0b4a6c09b5a4fa10f6 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 22 Nov 2024 15:22:07 -0500 Subject: [PATCH 098/107] linted --- .readthedocs.yaml | 3 --- docs/post_build.py | 38 -------------------------------------- docs/pre_build.py | 21 --------------------- 3 files changed, 62 deletions(-) delete mode 100644 docs/post_build.py delete mode 100644 docs/pre_build.py diff --git a/.readthedocs.yaml b/.readthedocs.yaml index a74d45cb..9487785e 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -13,10 +13,7 @@ build: jobs: pre_build: - gem install html-proofer -v ">= 5.0.9" # Ensure version >= 5.0.9 - - python docs/pre_build.py post_build: - - python docs/pre_build.py - - python docs/post_build.py # Check everything except 403s and a jneurosci, which returns 404 but the link works when clicking. - htmlproofer $READTHEDOCS_OUTPUT/html --checks Links,Scripts,Images --ignore-urls "https://fonts.gstatic.com,https://www.jneurosci.org/content/25/47/11003" --assume-extension --check-external-hash --ignore-status-codes 403 --ignore-files "/.+\/_static\/.+/","/.+\/stubs\/.+/","/.+\/tutorials/plot_02_head_direction.+/" # The auto-generated animation doesn't have a alt or src/srcset; I am able to ignore missing alt, but I cannot work around a missing src/srcset diff --git a/docs/post_build.py b/docs/post_build.py deleted file mode 100644 index 9ee60031..00000000 --- a/docs/post_build.py +++ /dev/null @@ -1,38 +0,0 @@ -import os -from pathlib import Path -import matplotlib.pyplot as plt - -# Get the READTHEDOCS_OUTPUT environment variable -root = os.environ.get("READTHEDOCS_OUTPUT") - -if root: - # Define the paths - root_path = Path(root) - static_path = root_path / "html/_static" - target_path = static_path / "thumbnails/how_to_guide" - - # Check if both directories exist - if static_path.exists() and target_path.exists(): - print(f"Both {static_path} and {target_path} exist. Plotting...") - - # Generate a sample plot - plt.figure() - plt.plot([1, 2, 3], [4, 5, 6], label="Sample Plot") - plt.legend() - plt.title("Post-Build Plot") - - # Save the plot in the target directory - plot_path = target_path / "post_build_plot.svg" - plt.savefig(plot_path) - print(f"Plot saved to {plot_path}") - - print(f"\nContents of {target_path}:") - for item in target_path.iterdir(): - if item.is_file(): - print(f"- File: {item.name}") - elif item.is_dir(): - print(f"- Directory: {item.name}") - else: - print(f"Either {static_path} or {target_path} does not exist.") -else: - print("READTHEDOCS_OUTPUT is not set. Skipping plot generation.") diff --git a/docs/pre_build.py b/docs/pre_build.py deleted file mode 100644 index 9cd2a52f..00000000 --- a/docs/pre_build.py +++ /dev/null @@ -1,21 +0,0 @@ -import os -from pathlib import Path - -# Get the READTHEDOCS_OUTPUT environment variable -rtd_output = os.environ.get("READTHEDOCS_OUTPUT") - -if rtd_output: - print(f"READTHEDOCS_OUTPUT is set: {rtd_output}") - - # Convert to a Path object for better handling - output_path = Path(rtd_output) - print(f"Path resolved as: {output_path}") - - # Example: Check if it exists - if output_path.exists(): - print(f"The path exists: {output_path}") - else: - print(f"The path does not exist: {output_path}") - -else: - print("READTHEDOCS_OUTPUT is not set.") From 8d11bd5e56b3b47410b431d7cf8bb4491f76296d Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 22 Nov 2024 15:49:55 -0500 Subject: [PATCH 099/107] added from future import annotations --- src/nemos/identifiability_constraints.py | 2 ++ src/nemos/simulation.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/nemos/identifiability_constraints.py b/src/nemos/identifiability_constraints.py index 4c97f170..cb665ec8 100644 --- a/src/nemos/identifiability_constraints.py +++ b/src/nemos/identifiability_constraints.py @@ -1,5 +1,7 @@ """Utility functions for applying identifiability constraints to rank deficient feature matrices.""" +from __future__ import annotations + from functools import partial from typing import Callable, Tuple diff --git a/src/nemos/simulation.py b/src/nemos/simulation.py index 76249966..a2dc06d6 100644 --- a/src/nemos/simulation.py +++ b/src/nemos/simulation.py @@ -1,5 +1,7 @@ """Utility functions for coupling filter definition.""" +from __future__ import annotations + from typing import Callable, Tuple, Union import jax From 664d500e37f4d87bcc7e931b33d449c50f81d358 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 22 Nov 2024 16:12:54 -0500 Subject: [PATCH 100/107] added sphinx build to gitignore --- .gitignore | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 514cff6f..eb0dc77e 100644 --- a/.gitignore +++ b/.gitignore @@ -117,8 +117,8 @@ venv.bak/ # Rope project settings .ropeproject -# mkdocs documentation -/site +# sphinx build documentation +/docs/_build # mypy .mypy_cache/ @@ -153,6 +153,4 @@ docs/data/ # rst generated files docs/stubs -# ignore the auto-generated svgs -docs/assets/thumbnails From c1984624e68536a6c6229f4e81f663b09af77f97 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 22 Nov 2024 16:14:38 -0500 Subject: [PATCH 101/107] copyright updated --- docs/_templates/layout.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html index 1ab3da93..9a987f9b 100644 --- a/docs/_templates/layout.html +++ b/docs/_templates/layout.html @@ -5,7 +5,7 @@

- {% trans copyright=copyright|e %}© Copyright {{ copyright }}, Edoardo Balzani.{% endtrans %}
+ {% trans copyright=copyright|e %}© Copyright {{ copyright }}, nemos authors.{% endtrans %}
Created using Sphinx and the PyData Theme.

From 3949c452954cf914981082185fc259233c52483a Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Fri, 22 Nov 2024 16:15:13 -0500 Subject: [PATCH 102/107] fixed name --- docs/background/plot_00_conceptual_intro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/background/plot_00_conceptual_intro.md b/docs/background/plot_00_conceptual_intro.md index afd6c08c..8074fff0 100644 --- a/docs/background/plot_00_conceptual_intro.md +++ b/docs/background/plot_00_conceptual_intro.md @@ -63,7 +63,7 @@ causation for you (causation being a notoriously difficult problem in science), but it will allow you to see the effect of adding and removing different inputs on the predicted firing rate, which can facilitate causal inferences. For more reading on causation and explanation in -neuroscience, the work of [CarlCraver](https://philosophy.wustl.edu/people/carl-f-craver) +neuroscience, the work of [Carl Craver](https://philosophy.wustl.edu/people/carl-f-craver) is a good place to start. ::: From a33361abe91d701760bae8c92e738baa9a8a8352 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Mon, 25 Nov 2024 09:10:04 -0500 Subject: [PATCH 103/107] fixed error multiline --- src/nemos/basis.py | 5 +++-- src/nemos/glm.py | 19 ++++++++++++------- src/nemos/observation_models.py | 8 +++++--- src/nemos/simulation.py | 7 +++---- src/nemos/utils.py | 5 +++-- 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/nemos/basis.py b/src/nemos/basis.py index 0b6eee9b..164936c7 100644 --- a/src/nemos/basis.py +++ b/src/nemos/basis.py @@ -1008,9 +1008,10 @@ def evaluate_on_grid(self, *n_samples: int) -> Tuple[Tuple[NDArray], NDArray]: Raises ------ ValueError - - If the time point number is inconsistent between inputs or if the number of inputs doesn't match what + If the time point number is inconsistent between inputs or if the number of inputs doesn't match what the Basis object requires. - - If one of the n_samples is <= 0. + ValueError + If one of the n_samples is <= 0. Notes ----- diff --git a/src/nemos/glm.py b/src/nemos/glm.py index d348028f..509d8beb 100644 --- a/src/nemos/glm.py +++ b/src/nemos/glm.py @@ -686,7 +686,7 @@ def fit( If ``init_params[i]`` cannot be converted to ``jnp.ndarray`` for all ``i`` Examples - ------- + -------- >>> # example input >>> import numpy as np >>> X, y = np.random.normal(size=(10, 2)), np.random.poisson(size=10) @@ -1516,12 +1516,17 @@ def fit( Raises ------ ValueError - - If ``init_params`` is not of length two. - - If dimensionality of ``init_params`` are not correct. - - If ``X`` is not two-dimensional. - - If ``y`` is not two-dimensional. - - If the ``feature_mask`` is not of the right shape. - - If solver returns at least one NaN parameter, which means it found + If ``init_params`` is not of length two. + ValueError + If dimensionality of ``init_params`` are not correct. + ValueError + If ``X`` is not two-dimensional. + ValueError + If ``y`` is not two-dimensional. + ValueError + If the ``feature_mask`` is not of the right shape. + ValueError + If solver returns at least one NaN parameter, which means it found an invalid solution. Try tuning optimization hyperparameters. TypeError If ``init_params`` are not array-like diff --git a/src/nemos/observation_models.py b/src/nemos/observation_models.py index e4bc407c..bea7b3d6 100644 --- a/src/nemos/observation_models.py +++ b/src/nemos/observation_models.py @@ -868,9 +868,11 @@ def check_observation_model(observation_model): If the `observation_model` does not have one of the required attributes. TypeError - - If an attribute is not a callable function. - - If a function does not return a jax.numpy.ndarray. - - If 'inverse_link_function' is not differentiable. + If an attribute is not a callable function. + TypeError + If a function does not return a jax.numpy.ndarray. + TypeError + If 'inverse_link_function' is not differentiable. Examples -------- diff --git a/src/nemos/simulation.py b/src/nemos/simulation.py index a2dc06d6..48af7008 100644 --- a/src/nemos/simulation.py +++ b/src/nemos/simulation.py @@ -60,8 +60,9 @@ def difference_of_gammas( Raises ------ ValueError: - - If any of the Gamma parameters is lesser or equal to 0. - - If the upper_percentile is not in [0, 1). + If any of the Gamma parameters is lesser or equal to 0. + ValueError: + If the upper_percentile is not in [0, 1). References ---------- @@ -247,7 +248,6 @@ def simulate_recurrent( inverse_link_function : The inverse link function for the observation model. - Returns ------- simulated_activity : @@ -294,7 +294,6 @@ def simulate_recurrent( >>> _ = plt.title("Simulated firing rates") >>> _ = plt.show() """ - if isinstance(feedforward_input, FeaturePytree): raise ValueError( "simulate_recurrent works only with arrays. " diff --git a/src/nemos/utils.py b/src/nemos/utils.py index 87ad0472..557b6c96 100644 --- a/src/nemos/utils.py +++ b/src/nemos/utils.py @@ -53,10 +53,11 @@ def validate_axis(tree: Any, axis: int): Raises ------ ValueError - - If the specified axis is equal to or greater than the number of dimensions (`ndim`) of any array + If the specified axis is equal to or greater than the number of dimensions (`ndim`) of any array within the tree. This ensures that operations intended for a specific axis can be safely performed on every array in the tree. - - If the axis is negative or non-integer. + ValueError + If the axis is negative or non-integer. """ if not isinstance(axis, int) or axis < 0: raise ValueError("`axis` must be a non negative integer.") From 56947140db976135c6293d389dcc7aa3814a3f95 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Mon, 25 Nov 2024 09:22:16 -0500 Subject: [PATCH 104/107] fixed rendering eqns --- docs/background/plot_00_conceptual_intro.md | 4 ++-- src/nemos/observation_models.py | 12 ++++++------ src/nemos/proximal_operator.py | 16 ++++++++-------- src/nemos/solvers/_svrg_defaults.py | 4 ++-- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/background/plot_00_conceptual_intro.md b/docs/background/plot_00_conceptual_intro.md index 8074fff0..49c4a250 100644 --- a/docs/background/plot_00_conceptual_intro.md +++ b/docs/background/plot_00_conceptual_intro.md @@ -227,13 +227,13 @@ likely it is to observe the given spike train for the computed firing rate: if $y(t)$ is the spike counts and $\lambda(t)$ the firing rate, the equation for the log-likelihood is -$$ \sum\_t \log P(y(t) | \lambda(t)) = \sum\_t y(t) \log(\lambda(t)) - +$$ \sum_t \log P(y(t) | \lambda(t)) = \sum_t y(t) \log(\lambda(t)) - \lambda(t) - \log (y(t)!)\tag{3}$$ Note that this last $\log(y(t)!)$ term does not depend on $\lambda(t)$ and thus is independent of the model, so it is normally ignored. -$$ \sum\_t \log P(y(t) | \lambda(t)) \propto \sum\_t y(t) \log(\lambda(t)) - +$$ \sum_t \log P(y(t) | \lambda(t)) \propto \sum_t y(t) \log(\lambda(t)) - \lambda(t))\tag{4}$$ This is the objective function of the GLM model: we are trying to find the diff --git a/src/nemos/observation_models.py b/src/nemos/observation_models.py index bea7b3d6..4a72d561 100644 --- a/src/nemos/observation_models.py +++ b/src/nemos/observation_models.py @@ -466,16 +466,16 @@ def _negative_log_likelihood( .. math:: \begin{aligned} \text{LL}(\hat{\lambda} | y) &= \frac{1}{T \cdot N} \sum_{n=1}^{N} \sum_{t=1}^{T} - [y\_{tn} \log(\hat{\lambda}\_{tn}) - \hat{\lambda}\_{tn} - \log({y\_{tn}!})] \\\ - &= \frac{1}{T \cdot N} \sum_{n=1}^{N} \sum_{t=1}^{T} [y\_{tn} \log(\hat{\lambda}\_{tn}) - - \hat{\lambda}\_{tn} - \Gamma({y\_{tn}+1})] \\\ - &= \frac{1}{T \cdot N} \sum_{n=1}^{N} \sum_{t=1}^{T} [y\_{tn} \log(\hat{\lambda}\_{tn}) - - \hat{\lambda}\_{tn}] + \\text{const} + [y_{tn} \log(\hat{\lambda}_{tn}) - \hat{\lambda}_{tn} - \log({y_{tn}!})] \\\ + &= \frac{1}{T \cdot N} \sum_{n=1}^{N} \sum_{t=1}^{T} [y_{tn} \log(\hat{\lambda}_{tn}) - + \hat{\lambda}_{tn} - \Gamma({y_{tn}+1})] \\\ + &= \frac{1}{T \cdot N} \sum_{n=1}^{N} \sum_{t=1}^{T} [y_{tn} \log(\hat{\lambda}_{tn}) - + \hat{\lambda}_{tn}] + \\text{const} \end{aligned} Because :math:`\Gamma(k+1)=k!`, see `wikipedia ` for explanation. - The :math:`\log({y\_{tn}!})` term is not a function of the parameters and can be disregarded + The :math:`\log({y_{tn}!})` term is not a function of the parameters and can be disregarded when computing the loss-function. This is why we incorporated it into the `const` term. """ predicted_rate = jnp.clip( diff --git a/src/nemos/proximal_operator.py b/src/nemos/proximal_operator.py index 51602ed5..dc4f5b6d 100644 --- a/src/nemos/proximal_operator.py +++ b/src/nemos/proximal_operator.py @@ -11,7 +11,7 @@ More formally, proximal operators solve the minimization problem, $$ -\\text{prox}\_f(\bm{v}) = \arg\min\_{\bm{x}} \left( f(\bm{x}) + \frac{1}{2}\Vert \bm{x} - \bm{v}\Vert_2 ^2 \right) +\\text{prox}_f(\bm{v}) = \arg\min_{\bm{x}} \left( f(\bm{x}) + \frac{1}{2}\Vert \bm{x} - \bm{v}\Vert_2 ^2 \right) $$ @@ -106,7 +106,7 @@ def prox_group_lasso( The proximal operator equation are, $$ - \text{prox}(\beta_g) = \text{min}_{\beta} \left[ \lambda \sum\_{g=1}^G \Vert \beta_g \Vert_2 + + \text{prox}(\beta_g) = \text{min}_{\beta} \left[ \lambda \sum_{g=1}^G \Vert \beta_g \Vert_2 + \frac{1}{2} \Vert \hat{\beta} - \beta \Vert_2^2 \right], $$ @@ -115,15 +115,15 @@ def prox_group_lasso( The analytical solution[$^{[1]}$](#references). for the beta is, $$ - \text{prox}(\beta\_g) = \max \left(1 - \frac{\lambda \sqrt{p\_g}}{\Vert \hat{\beta}\_g \Vert_2}, - 0\right) \cdot \hat{\beta}\_g, + \text{prox}(\beta_g) = \max \left(1 - \frac{\lambda \sqrt{p_g}}{\Vert \hat{\beta}_g \Vert_2}, + 0\right) \cdot \hat{\beta}_g, $$ - where $p_g$ is the dimensionality of $\beta\_g$ and $\hat{\beta}$ is typically the gradient step + where $p_g$ is the dimensionality of $\beta_g$ and $\hat{\beta}$ is typically the gradient step of the un-regularized optimization objective function. It's easy to see how the group-Lasso proximal operator acts as a shrinkage factor for the un-penalize update, and the half-rectification non-linearity that effectively sets to zero group of coefficients satisfying, $$ - \Vert \hat{\beta}\_g \Vert_2 \le \frac{1}{\lambda \sqrt{p\_g}}. + \Vert \hat{\beta}_g \Vert_2 \le \frac{1}{\lambda \sqrt{p_g}}. $$ # References @@ -154,8 +154,8 @@ def prox_lasso(x: Any, l1reg: Optional[Any] = None, scaling: float = 1.0) -> Any Minimizes the following function: $$ - \underset{y}{\text{argmin}} ~ \frac{1}{2} ||x - y||\_2^2 - + \text{scaling} \cdot \text{l1reg} \cdot ||y||\_1 + \underset{y}{\text{argmin}} ~ \frac{1}{2} ||x - y||_2^2 + + \text{scaling} \cdot \text{l1reg} \cdot ||y||_1 $$ When `l1reg` is a pytree, the weights are applied coordinate-wise. diff --git a/src/nemos/solvers/_svrg_defaults.py b/src/nemos/solvers/_svrg_defaults.py index a12d1098..47aea11d 100644 --- a/src/nemos/solvers/_svrg_defaults.py +++ b/src/nemos/solvers/_svrg_defaults.py @@ -422,7 +422,7 @@ def _calculate_optimal_batch_size_svrg( num_samples: The number of samples. l_smooth_max: - The $L\_{\text{max}}$ smoothness constant. + The $L_{\text{max}}$ smoothness constant. l_smooth: The $L$ smoothness constant. strong_convexity: @@ -480,7 +480,7 @@ def _calculate_b_hat(num_samples: int, l_smooth_max: float, l_smooth: float): num_samples : Total number of data points. l_smooth_max : - Maximum smoothness constant $L\_{\text{max}}$. + Maximum smoothness constant $L_{\text{max}}$. l_smooth : Smoothness constant $L$. From 3b884d1f31028667ce34f2681a667f97f92dcdcf Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Mon, 25 Nov 2024 09:54:44 -0500 Subject: [PATCH 105/107] last fixes --- docs/background/plot_01_1D_basis_function.md | 6 +++--- docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md | 2 +- docs/tutorials/plot_01_current_injection.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/background/plot_01_1D_basis_function.md b/docs/background/plot_01_1D_basis_function.md index 3e69e301..4d823717 100644 --- a/docs/background/plot_01_1D_basis_function.md +++ b/docs/background/plot_01_1D_basis_function.md @@ -86,7 +86,7 @@ print(f"Evaluated B-spline of order {order} with {eval_basis.shape[1]} " fig = plt.figure() plt.title("B-spline basis") -_ = plt.plot(eval_basis) +plt.plot(samples, eval_basis); ``` ```{code-cell} ipython3 @@ -133,9 +133,9 @@ the fixed range basis. ```{code-cell} ipython3 fig, axs = plt.subplots(2,1, sharex=True) plt.suptitle("B-spline basis ") -axs[0].plot(bspline(samples), color="k") +axs[0].plot(samples, bspline(samples), color="k") axs[0].set_title("default") -axs[1].plot(bspline_range(samples), color="tomato") +axs[1].plot(samples, bspline_range(samples), color="tomato") axs[1].set_title("bounds=[0.2, 0.8]") plt.tight_layout() ``` diff --git a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md index c72c1037..572aca9d 100644 --- a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md +++ b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md @@ -438,7 +438,7 @@ if path.exists(): fig.savefig(path / "plot_05_sklearn_pipeline_cv_demo.svg") ``` -:rocket::rocket::rocket: **Success!** :rocket::rocket::rocket: +_U+1F680 _U+1F680 _U+1F680 **Success!** _U+1F680 _U+1F680 _U+1F680 We are now able to capture the distribution of the firing rate appropriately: both peaks and valleys in the spiking activity are matched by our model predicitons. ### Evaluating different bases directly diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md index d52119be..a13322a5 100644 --- a/docs/tutorials/plot_01_current_injection.md +++ b/docs/tutorials/plot_01_current_injection.md @@ -404,7 +404,7 @@ current). We can easily plot the tuning curve of the neuron: ```{code-cell} ipython3 -doc_plots.tuning_curve_plot(tuning_curve) +doc_plots.tuning_curve_plot(tuning_curve); ``` We can see that, while the firing rate mostly increases with the current, From 7dcb4581af55f6fc50a295f5812fdcbc3910d8d8 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Mon, 25 Nov 2024 11:14:38 -0500 Subject: [PATCH 106/107] fixed emojis --- .../plot_05_sklearn_pipeline_cv_demo.md | 3 ++- docs/tutorials/plot_01_current_injection.md | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md index 572aca9d..7684857c 100644 --- a/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md +++ b/docs/how_to_guide/plot_05_sklearn_pipeline_cv_demo.md @@ -438,7 +438,8 @@ if path.exists(): fig.savefig(path / "plot_05_sklearn_pipeline_cv_demo.svg") ``` -_U+1F680 _U+1F680 _U+1F680 **Success!** _U+1F680 _U+1F680 _U+1F680 +🚀🚀🚀 **Success!** 🚀🚀🚀 + We are now able to capture the distribution of the firing rate appropriately: both peaks and valleys in the spiking activity are matched by our model predicitons. ### Evaluating different bases directly diff --git a/docs/tutorials/plot_01_current_injection.md b/docs/tutorials/plot_01_current_injection.md index a13322a5..70ebac16 100644 --- a/docs/tutorials/plot_01_current_injection.md +++ b/docs/tutorials/plot_01_current_injection.md @@ -444,14 +444,14 @@ following properties: arrays, `numpy` arrays or `pynapple` `TsdFrame`/`Tsd`. :::{admonition} What is jax? -:class: info - - [jax](https://github.com/google/jax) is a Google-supported python library - for automatic differentiation. It has all sorts of neat features, but the - most relevant of which for NeMoS is its GPU-compatibility and - just-in-time compilation (both of which make code faster with little - overhead!), as well as the collection of optimizers present in - [jaxopt](https://jaxopt.github.io/stable/). +:class: note + +[jax](https://github.com/google/jax) is a Google-supported python library +for automatic differentiation. It has all sorts of neat features, but the +most relevant of which for NeMoS is its GPU-compatibility and +just-in-time compilation (both of which make code faster with little +overhead!), as well as the collection of optimizers present in +[jaxopt](https://jaxopt.github.io/stable/). ::: First, we require that our predictors and our spike counts have the same From bfb8f16112da4c4b74222509c881c8cd8bccc4f3 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Wed, 27 Nov 2024 16:59:03 -0500 Subject: [PATCH 107/107] exclude site brain map --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 9487785e..ecaca19d 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -15,7 +15,7 @@ build: - gem install html-proofer -v ">= 5.0.9" # Ensure version >= 5.0.9 post_build: # Check everything except 403s and a jneurosci, which returns 404 but the link works when clicking. - - htmlproofer $READTHEDOCS_OUTPUT/html --checks Links,Scripts,Images --ignore-urls "https://fonts.gstatic.com,https://www.jneurosci.org/content/25/47/11003" --assume-extension --check-external-hash --ignore-status-codes 403 --ignore-files "/.+\/_static\/.+/","/.+\/stubs\/.+/","/.+\/tutorials/plot_02_head_direction.+/" + - htmlproofer $READTHEDOCS_OUTPUT/html --checks Links,Scripts,Images --ignore-urls "https://fonts.gstatic.com,https://celltypes.brain-map.org/experiment/electrophysiology/478498617,https://www.jneurosci.org/content/25/47/11003" --assume-extension --check-external-hash --ignore-status-codes 403 --ignore-files "/.+\/_static\/.+/","/.+\/stubs\/.+/","/.+\/tutorials/plot_02_head_direction.+/" # The auto-generated animation doesn't have a alt or src/srcset; I am able to ignore missing alt, but I cannot work around a missing src/srcset # therefore for this file I am not checking the figures. - htmlproofer $READTHEDOCS_OUTPUT/html/tutorials/plot_02_head_direction.html --checks Links,Scripts --ignore-urls "https://www.jneurosci.org/content/25/47/11003"