From 72c457e32c9fe9e21c2525d3811dc7570564ce5f Mon Sep 17 00:00:00 2001 From: Barbier--Darnal Joseph Date: Sun, 15 Mar 2026 19:33:05 +0100 Subject: [PATCH 1/5] fix a bunch of issues --- AGENT.md => AGENTS.md | 0 plotjs/plotjs.py | 45 ++++++++++----- pyproject.toml | 2 +- tests/test-python/test_plotjs.py | 51 +++++++++++++++++ uv.lock | 95 ++++++++------------------------ 5 files changed, 105 insertions(+), 88 deletions(-) rename AGENT.md => AGENTS.md (100%) diff --git a/AGENT.md b/AGENTS.md similarity index 100% rename from AGENT.md rename to AGENTS.md diff --git a/plotjs/plotjs.py b/plotjs/plotjs.py index 21f653d..2b97426 100644 --- a/plotjs/plotjs.py +++ b/plotjs/plotjs.py @@ -23,6 +23,8 @@ JS_PARSER_PATH: str = os.path.join(TEMPLATE_DIR, "plotparser.js") env: Environment = Environment(loader=FileSystemLoader(TEMPLATE_DIR)) +DEFAULT_FAVICON_PATH = "https://github.com/JosephBARBIERDARNAL/static/blob/main/python-libs/plotjs/favicon.ico?raw=true" +DEFAULT_DOCUMENT_TITLE = "Made with plotjs" class PlotJS: @@ -51,11 +53,13 @@ def __init__( # https://github.com/y-sunflower/plotjs/issues/54 old_svg_hashsalt = plt.rcParams["svg.hashsalt"] old_svg_id = plt.rcParams["svg.id"] - plt.rcParams["svg.hashsalt"] = "svg-hashsalt" - plt.rcParams["svg.id"] = "svg-id" - fig.savefig(buf, format="svg", **savefig_kws) - plt.rcParams["svg.hashsalt"] = old_svg_hashsalt - plt.rcParams["svg.id"] = old_svg_id + try: + plt.rcParams["svg.hashsalt"] = "svg-hashsalt" + plt.rcParams["svg.id"] = "svg-id" + fig.savefig(buf, format="svg", **savefig_kws) + finally: + plt.rcParams["svg.hashsalt"] = old_svg_hashsalt + plt.rcParams["svg.id"] = old_svg_id buf.seek(0) self._svg_content = buf.getvalue() @@ -68,6 +72,8 @@ def __init__( self.additional_css = "" self.additional_javascript = "" self._hover_nearest = False + self._favicon_path = DEFAULT_FAVICON_PATH + self._document_title = DEFAULT_DOCUMENT_TITLE self._template = env.get_template("template.html") with open(CSS_PATH) as f: @@ -181,7 +187,13 @@ def add_tooltip( normalized_on.append(element) if ax is None: + if not self._axes: + raise ValueError("Cannot add tooltip because the figure has no Axes.") ax: Axes = self._axes[0] + elif ax not in self._axes: + raise ValueError( + "Cannot add tooltip on an Axes that does not belong to this figure." + ) self._legend_handles, self._legend_handles_labels = ( ax.get_legend_handles_labels() ) @@ -338,8 +350,8 @@ def add_d3js(self, version: int = 7) -> "PlotJS": def save( self, file_path: str, - favicon_path: str = "https://github.com/JosephBARBIERDARNAL/static/blob/main/python-libs/plotjs/favicon.ico?raw=true", - document_title: str = "Made with plotjs", + favicon_path: str = DEFAULT_FAVICON_PATH, + document_title: str = DEFAULT_DOCUMENT_TITLE, ) -> "PlotJS": """ Save the interactive matplotlib plots to an HTML file. @@ -371,7 +383,7 @@ def save( if not file_path.endswith(".html"): file_path += ".html" - with open(file_path, "w") as f: + with open(file_path, "w", encoding="utf-8") as f: f.write(self.html) # store the file path for later use (e.g., show() method) @@ -427,18 +439,23 @@ def show(self) -> "PlotJS": ``` """ if not hasattr(self, "_file_path"): - temp_file = tempfile.NamedTemporaryFile( - mode="w", suffix=".html", delete=False - ) - self.save(temp_file.name) - temp_file.close() + temp_fd, temp_path = tempfile.mkstemp(suffix=".html") + os.close(temp_fd) + self.save(temp_path) webbrowser.open(f"file://{self._file_path}") return self def _set_plot_data_json(self) -> None: if not hasattr(self, "_tooltip_labels"): - self.add_tooltip() + if self._axes: + self.add_tooltip() + else: + self._tooltip_labels = [] + self._tooltip_groups = [] + self._tooltip_x_shift = 0 + self._tooltip_y_shift = 0 + self._axes_tooltip = {} self.plot_data_json = { "tooltip_labels": self._tooltip_labels, diff --git a/pyproject.toml b/pyproject.toml index 0079498..d4597c1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,6 @@ plotjs = { workspace = true } [dependency-groups] dev = [ - "pre-commit>=4.2.0", "pytest>=8.3.5", "ruff>=0.11.13", "mkdocs-material>=9.6.9", @@ -57,6 +56,7 @@ dev = [ "highlight-text>=0.2", "drawarrow>=0.1.0", "playwright>=1.40.0", + "prek>=0.3.5", ] [project.urls] diff --git a/tests/test-python/test_plotjs.py b/tests/test-python/test_plotjs.py index af277a5..5ef595a 100644 --- a/tests/test-python/test_plotjs.py +++ b/tests/test-python/test_plotjs.py @@ -356,3 +356,54 @@ def test_add_tooltip_on_parameter_invalid_in_list(): PlotJS(fig=fig).add_tooltip(labels=["A", "B", "C"], on=["point", "circle"]) plt.close(fig) + + +def test_as_html_without_save_uses_default_metadata(): + fig, ax = plt.subplots() + ax.scatter([1, 2, 3], [1, 2, 3]) + + html = PlotJS(fig=fig).as_html() + + assert "Made with plotjs" in html + assert 'rel="icon"' in html + assert " Date: Sun, 15 Mar 2026 20:06:25 +0100 Subject: [PATCH 2/5] migrate to zensical --- .gitignore | 1 + docs/developers/contributing.md | 2 +- docs/stylesheets/style.css | 9 ++-- justfile | 2 +- mkdocs.yaml | 95 --------------------------------- plotjs/data/__init__.py | 2 +- pyproject.toml | 2 + uv.lock | 57 ++++++++++++++++++++ zensical.toml | 81 ++++++++++++++++++++++++++++ 9 files changed, 150 insertions(+), 101 deletions(-) delete mode 100644 mkdocs.yaml create mode 100644 zensical.toml diff --git a/.gitignore b/.gitignore index 0e5f481..8d7c412 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,4 @@ release.sh node_modules bun.lockb .claude/ +site/ diff --git a/docs/developers/contributing.md b/docs/developers/contributing.md index 3d9efc3..b37f659 100644 --- a/docs/developers/contributing.md +++ b/docs/developers/contributing.md @@ -36,7 +36,7 @@ git checkout -b my-feature ```bash uv sync --all-groups --dev -uv run pre-commit install +uv run prek install -f uv pip install -e . ``` diff --git a/docs/stylesheets/style.css b/docs/stylesheets/style.css index 2b07eea..e50b048 100644 --- a/docs/stylesheets/style.css +++ b/docs/stylesheets/style.css @@ -5,9 +5,12 @@ h4 { } footer.custom-footer { - box-shadow: 0 0 1rem #0000003e, 0 0.2rem 0.4rem #0003; - transition: transform 0.25s cubic-bezier(0.1, 0.7, 0.1, 1), box-shadow 0.25s; - color: #000000ff; + box-shadow: + 0 0 1rem #0000003e, + 0 0.2rem 0.4rem #0003; + transition: + transform 0.25s cubic-bezier(0.1, 0.7, 0.1, 1), + box-shadow 0.25s; padding: 20px 20px; text-align: center; margin-top: 50px; diff --git a/justfile b/justfile index af5ca23..1a0d5c5 100644 --- a/justfile +++ b/justfile @@ -28,7 +28,7 @@ cov: rm coverage.xml preview: - uv run mkdocs serve + uv run zensical serve jsdoc: bun run docs:js diff --git a/mkdocs.yaml b/mkdocs.yaml deleted file mode 100644 index 4272c84..0000000 --- a/mkdocs.yaml +++ /dev/null @@ -1,95 +0,0 @@ -site_name: plotjs -site_url: https://y-sunflower.github.io/plotjs/ -repo_url: https://github.com/y-sunflower/plotjs - -theme: - name: material - font: - text: Inter - code: Jetbrains Mono - palette: - # Palette toggle for automatic mode - - media: "(prefers-color-scheme)" - toggle: - icon: material/brightness-auto - name: Switch to light mode - - # Palette toggle for light mode - - media: "(prefers-color-scheme: light)" - scheme: default - toggle: - icon: material/brightness-7 - name: Switch to dark mode - - # Palette toggle for dark mode - - media: "(prefers-color-scheme: dark)" - scheme: slate - toggle: - icon: material/brightness-4 - name: Switch to system preference - logo: https://github.com/JosephBARBIERDARNAL/static/blob/main/python-libs/plotjs/image.png?raw=true - custom_dir: overrides - favicon: https://github.com/JosephBARBIERDARNAL/static/blob/main/python-libs/plotjs/favicon.ico?raw=true - features: - - content.code.copy - - navigation.path - - content.footnote.tooltips - - navigation.expand - icon: - repo: fontawesome/brands/github - -plugins: - - search - - mkdocstrings: - default_handler: python - handlers: - python: - options: - show_source: false - show_root_heading: true - heading_level: 3 - -nav: - - Home: index.md - - Gallery: gallery/index.md - - Guides: - - Add your own CSS: guides/css/index.md - - Add your own JavaScript: guides/javascript/index.md - - Embed graphs in different environments: guides/embed-graphs/index.md - - Troubleshooting: guides/troubleshooting/index.md - - Advanced: guides/advanced/index.md - - API Reference: - - PlotJS: reference/plotjs.md - - CSS: reference/css.md - - JavaScript: reference/javascript.md - - Datasets: reference/datasets.md - - For developers: - - Overview: developers/overview.md - - Parsing matplotlib's SVG: developers/parsing-matplotlib-svg.md - - SVG parser reference: developers/svg-parser-reference.md - - Contributing: developers/contributing.md - -extra_css: - - stylesheets/style.css - -markdown_extensions: - - pymdownx.tabbed: - alternate_style: true - - pymdownx.highlight: - anchor_linenums: true - line_spans: __span - pygments_lang_class: true - - pymdownx.inlinehilite - - footnotes - - pymdownx.snippets - - pymdownx.superfences - - attr_list - - md_in_html - - pymdownx.blocks.caption - - admonition - - pymdownx.details - - pymdownx.critic - - pymdownx.caret - - pymdownx.keys - - pymdownx.mark - - pymdownx.tilde diff --git a/plotjs/data/__init__.py b/plotjs/data/__init__.py index c3fd222..6074032 100644 --- a/plotjs/data/__init__.py +++ b/plotjs/data/__init__.py @@ -1,3 +1,3 @@ -from .datasets import load_iris, load_mtcars, load_titanic, _load_data +from plotjs.data.datasets import load_iris, load_mtcars, load_titanic, _load_data __all__: list[str] = ["load_iris", "load_mtcars", "_load_data", "load_titanic"] diff --git a/pyproject.toml b/pyproject.toml index d4597c1..5ebdca4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,6 +57,8 @@ dev = [ "drawarrow>=0.1.0", "playwright>=1.40.0", "prek>=0.3.5", + "seaborn>=0.13.2", + "zensical>=0.0.27", ] [project.urls] diff --git a/uv.lock b/uv.lock index 543577f..b3fc884 100644 --- a/uv.lock +++ b/uv.lock @@ -648,6 +648,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, ] +[[package]] +name = "deepmerge" +version = "2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a8/3a/b0ba594708f1ad0bc735884b3ad854d3ca3bdc1d741e56e40bbda6263499/deepmerge-2.0.tar.gz", hash = "sha256:5c3d86081fbebd04dd5de03626a0607b809a98fb6ccba5770b62466fe940ff20", size = 19890, upload-time = "2024-08-30T05:31:50.308Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/82/e5d2c1c67d19841e9edc74954c827444ae826978499bde3dfc1d007c8c11/deepmerge-2.0-py3-none-any.whl", hash = "sha256:6de9ce507115cff0bed95ff0ce9ecc31088ef50cbdf09bc90a09349a318b3d00", size = 13475, upload-time = "2024-08-30T05:31:48.659Z" }, +] + [[package]] name = "defusedxml" version = "0.7.1" @@ -2256,7 +2265,9 @@ dev = [ { name = "pypalettes" }, { name = "pytest" }, { name = "ruff" }, + { name = "seaborn" }, { name = "ty" }, + { name = "zensical" }, ] [package.metadata] @@ -2288,7 +2299,9 @@ dev = [ { name = "pypalettes", specifier = ">=0.1.4" }, { name = "pytest", specifier = ">=8.3.5" }, { name = "ruff", specifier = ">=0.11.13" }, + { name = "seaborn", specifier = ">=0.13.2" }, { name = "ty", specifier = ">=0.0.1a16" }, + { name = "zensical", specifier = ">=0.0.27" }, ] [[package]] @@ -3029,6 +3042,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6e/6c/a76329897a7cae4937d403e623aa6aaea616a0bb5b36588f0b9d1c9a3739/scipy-1.16.1-cp314-cp314t-win_amd64.whl", hash = "sha256:c0c804d60492a0aad7f5b2bb1862f4548b990049e27e828391ff2bf6f7199998", size = 39427705, upload-time = "2025-07-27T16:31:53.96Z" }, ] +[[package]] +name = "seaborn" +version = "0.13.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "matplotlib" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "numpy", version = "2.3.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "pandas" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/86/59/a451d7420a77ab0b98f7affa3a1d78a313d2f7281a57afb1a34bae8ab412/seaborn-0.13.2.tar.gz", hash = "sha256:93e60a40988f4d65e9f4885df477e2fdaff6b73a9ded434c1ab356dd57eefff7", size = 1457696, upload-time = "2024-01-25T13:21:52.551Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987", size = 294914, upload-time = "2024-01-25T13:21:49.598Z" }, +] + [[package]] name = "send2trash" version = "1.8.3" @@ -3374,3 +3402,32 @@ sdist = { url = "https://files.pythonhosted.org/packages/41/53/2e0253c5efd69c965 wheels = [ { url = "https://files.pythonhosted.org/packages/ca/51/5447876806d1088a0f8f71e16542bf350918128d0a69437df26047c8e46f/widgetsnbextension-4.0.14-py3-none-any.whl", hash = "sha256:4875a9eaf72fbf5079dc372a51a9f268fc38d46f767cbf85c43a36da5cb9b575", size = 2196503, upload-time = "2025-04-10T13:01:23.086Z" }, ] + +[[package]] +name = "zensical" +version = "0.0.27" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "deepmerge" }, + { name = "markdown" }, + { name = "pygments" }, + { name = "pymdown-extensions" }, + { name = "pyyaml" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8f/83/969152d927b522a0fed1f20b1730575d86b920ce51530b669d9fad4537de/zensical-0.0.27.tar.gz", hash = "sha256:6d8d74aba4a9f9505e6ba1c43d4c828ba4ff7bb1ff9b005e5174c5b92cf23419", size = 3841776, upload-time = "2026-03-13T17:56:14.494Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d8/fe/0335f1a521eb6c0ab96028bf67148390eb1d5c742c23e6a4b0f8381508bd/zensical-0.0.27-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:d51ebf4b038f3eea99fd337119b99d92ad92bbe674372d5262e6dbbabbe4e9b5", size = 12262017, upload-time = "2026-03-13T17:55:36.403Z" }, + { url = "https://files.pythonhosted.org/packages/02/cb/ac24334fc7959b49496c97cb9d2bed82a8db8b84eafaf68189048e7fe69a/zensical-0.0.27-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:a627cd4599cf2c5a5a5205f0510667227d1fe4579b6f7445adba2d84bab9fbc8", size = 12147361, upload-time = "2026-03-13T17:55:39.736Z" }, + { url = "https://files.pythonhosted.org/packages/a2/0f/31c981f61006fdaf0460d15bde1248a045178d67307bad61a4588414855d/zensical-0.0.27-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99cbc493022f8749504ef10c71772d360b705b4e2fd1511421393157d07bdccf", size = 12505771, upload-time = "2026-03-13T17:55:42.993Z" }, + { url = "https://files.pythonhosted.org/packages/30/1e/f6842c94ec89e5e9184f407dbbab2a497b444b28d4fb5b8df631894be896/zensical-0.0.27-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ecc20a85e8a23ad9ab809b2f268111321be7b2e214021b3b00f138936a87a434", size = 12455689, upload-time = "2026-03-13T17:55:46.055Z" }, + { url = "https://files.pythonhosted.org/packages/4c/ad/866c3336381cca7528e792469958fbe2e65b9206a2657bef3dd8ed4ac88b/zensical-0.0.27-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da11e0f0861dbd7d3b5e6fe1e3a53b361b2181c53f3abe9fb4cdf2ed0cea47bf", size = 12791263, upload-time = "2026-03-13T17:55:49.193Z" }, + { url = "https://files.pythonhosted.org/packages/e5/df/fca5ed6bebdb61aa656dfa65cce4b4d03324a79c75857728230872fbdf7c/zensical-0.0.27-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e11d220181477040a4b22bf2b8678d5b0c878e7aae194fad4133561cb976d69", size = 12549796, upload-time = "2026-03-13T17:55:52.55Z" }, + { url = "https://files.pythonhosted.org/packages/4a/e2/43398b5ec64ed78204a5a5929a3990769fc0f6a3094a30395882bda1399a/zensical-0.0.27-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:06b9e308aec8c5db1cd623e2e98e1b25c3f5cab6b25fcc9bac1e16c0c2b93837", size = 12683568, upload-time = "2026-03-13T17:55:56.151Z" }, + { url = "https://files.pythonhosted.org/packages/b3/3c/5c98f9964c7e30735aacd22a389dacec12bcc5bc8162c58e76b76d20db6e/zensical-0.0.27-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:682085155126965b091cb9f915cd2e4297383ac500122fd4b632cf4511733eb2", size = 12725214, upload-time = "2026-03-13T17:55:59.286Z" }, + { url = "https://files.pythonhosted.org/packages/50/0f/ebaa159cac6d64b53bf7134420c2b43399acc7096cb79795be4fb10768fc/zensical-0.0.27-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:b367c285157c8e1099ae9e2b36564e07d3124bf891e96194a093bc836f3058d2", size = 12860416, upload-time = "2026-03-13T17:56:02.456Z" }, + { url = "https://files.pythonhosted.org/packages/88/06/d82bfccbf5a1f43256dbc4d1984e398035a65f84f7c1e48b69ba15ea7281/zensical-0.0.27-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:847c881209e65e1db1291c59a9db77966ac50f7c66bf9a733c3c7832144dbfca", size = 12819533, upload-time = "2026-03-13T17:56:05.487Z" }, + { url = "https://files.pythonhosted.org/packages/4d/1f/d25e421d91f063a9404c59dd032f65a67c7c700e9f5f40436ab98e533482/zensical-0.0.27-cp310-abi3-win32.whl", hash = "sha256:f31ec13c700794be3f9c0b7d90f09a7d23575a3a27c464994b9bb441a22d880b", size = 11862822, upload-time = "2026-03-13T17:56:08.933Z" }, + { url = "https://files.pythonhosted.org/packages/5a/b5/5b86d126fcc42b96c5dbecde5074d6ea766a1a884e3b25b3524843c5e6a5/zensical-0.0.27-cp310-abi3-win_amd64.whl", hash = "sha256:9d3b1fca7ea99a7b2a8db272dd7f7839587c4ebf4f56b84ff01c97b3893ec9f8", size = 12059658, upload-time = "2026-03-13T17:56:11.859Z" }, +] diff --git a/zensical.toml b/zensical.toml new file mode 100644 index 0000000..c407405 --- /dev/null +++ b/zensical.toml @@ -0,0 +1,81 @@ +[project] +site_name = "PlotJS" +repo_url = "https://github.com/y-sunflower/plotjs" +site_url = "https://y-sunflower.github.io/plotjs/" +site_description = "Turn static matplotlib charts into interactive web visualizations" +site_author = "Joseph Barbier" +copyright = """ +Copyright © 2026 Yellow Sunflower +""" +extra_css = ["stylesheets/style.css"] +nav = [ + { "Home" = "index.md" }, + { "Gallery" = "gallery/index.md" }, + { "Guides" = [ + "guides/css/index.md", + "guides/javascript/index.md", + "guides/embed-graphs/index.md", + "guides/troubleshooting/index.md", + "guides/advanced/index.md", + ] }, + { "API Reference" = [ + "reference/plotjs.md", + "reference/css.md", + "reference/javascript.md", + "reference/datasets.md", + ] }, + { "For developers" = [ + "developers/overview.md", + "developers/parsing-matplotlib-svg.md", + "developers/svg-parser-reference.md", + "developers/contributing.md", + ] }, +] + +[project.theme] +language = "en" +favicon = "images/favicon.png" +custom_dir = "overrides" +logo = "https://github.com/JosephBARBIERDARNAL/static/blob/main/python-libs/plotjs/image.png?raw=true" +features = [ + "announce.dismiss", + "content.code.annotate", + "content.code.copy", + "content.code.select", + "content.footnote.tooltips", + "content.tooltips", + "navigation.footer", + "navigation.indexes", + "navigation.instant", + "navigation.instant.prefetch", + "navigation.path", + "navigation.tabs", + "navigation.sections", + "navigation.top", + "navigation.tracking", + "search.highlight", + "navigation.prune", +] + +[[project.theme.palette]] +scheme = "default" +toggle.icon = "lucide/sun" +toggle.name = "Switch to dark mode" + +[[project.theme.palette]] +scheme = "slate" +toggle.icon = "lucide/moon" +toggle.name = "Switch to light mode" + +[project.theme.icon] +repo = "fontawesome/brands/github" +favicon = "https://github.com/JosephBARBIERDARNAL/static/blob/main/python-libs/plotjs/favicon.ico?raw=true" + +[project.plugins.mkdocstrings.handlers.python] +inventories = ["https://docs.python.org/3/objects.inv"] +paths = ["."] + +[project.plugins.mkdocstrings.handlers.python.options] +docstring_style = "google" +inherited_members = true +show_source = false From 121b8874422c6d49074a0dfed964d3fe1d3aeed7 Mon Sep 17 00:00:00 2001 From: Barbier--Darnal Joseph Date: Sun, 15 Mar 2026 20:06:58 +0100 Subject: [PATCH 3/5] migrate to zensical --- .github/workflows/doc.yaml | 43 +++++++++++++++----------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/.github/workflows/doc.yaml b/.github/workflows/doc.yaml index abfcaf5..64cd7ab 100644 --- a/.github/workflows/doc.yaml +++ b/.github/workflows/doc.yaml @@ -1,41 +1,32 @@ -name: Build and deploy doc - +name: Deploy on: push: - branches: [main] + branches: + - main permissions: contents: write +concurrency: + group: gh-pages + cancel-in-progress: true + jobs: deploy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - name: Configure Git Credentials - run: | - git config user.name github-actions[bot] - git config user.email 41898282+github-actions[bot]@users.noreply.github.com + - uses: actions/checkout@v5 - uses: actions/setup-python@v5 with: python-version: 3.x - - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV - - uses: actions/cache@v4 - with: - key: mkdocs-material-${{ env.cache_id }} - path: .cache - restore-keys: | - mkdocs-material- + - run: pip install zensical + - run: zensical build --clean + - name: Add CNAME for custom domain + run: echo "typst-in-production.com" > site/CNAME - - name: Install uv - uses: astral-sh/setup-uv@v5 + - name: Deploy to gh-pages + uses: peaceiris/actions-gh-pages@v4 with: - enable-cache: true - - - name: Install the project - run: uv sync --all-groups - - - name: Deploy MkDocs - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: PYTHONPATH=$(pwd) uv run mkdocs gh-deploy --force + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_branch: gh-pages + publish_dir: site From 09bd584387528eebdb7dffdfae9087aff4e48eb4 Mon Sep 17 00:00:00 2001 From: Barbier--Darnal Joseph Date: Sun, 15 Mar 2026 20:59:28 +0100 Subject: [PATCH 4/5] fix legend ignored in area charts #9 --- .github/workflows/doc.yaml | 2 - README.md | 234 + docs/developers/svg-parser-reference.md | 21 +- docs/iframes/CSS-2.html | 42 +- docs/iframes/CSS.html | 42 +- docs/iframes/area-natural-disasters.html | 42 +- docs/iframes/bug.html | 42 +- docs/iframes/javascript.html | 42 +- docs/iframes/javascript2.html | 42 +- docs/iframes/quickstart.html | 42 +- docs/iframes/quickstart10.html | 42 +- docs/iframes/quickstart11.html | 42 +- docs/iframes/quickstart2.html | 42 +- docs/iframes/quickstart3.html | 42 +- docs/iframes/quickstart4.html | 42 +- docs/iframes/quickstart5.html | 1590 +- docs/iframes/quickstart6.html | 42 +- docs/iframes/quickstart7.html | 42 +- docs/iframes/quickstart8.html | 42 +- docs/iframes/quickstart9.html | 42 +- docs/iframes/random-walk-1.html | 75415 ++++++++-------- plotjs/plotjs.py | 8 +- plotjs/static/plotparser.js | 40 +- tests/test-browser/test_interactions.py | 45 + tests/test-javascript/ParserSelectors.test.js | 36 + tests/test-javascript/ParserSetHover.test.js | 59 + 26 files changed, 39360 insertions(+), 38762 deletions(-) diff --git a/.github/workflows/doc.yaml b/.github/workflows/doc.yaml index 64cd7ab..5a22095 100644 --- a/.github/workflows/doc.yaml +++ b/.github/workflows/doc.yaml @@ -21,8 +21,6 @@ jobs: python-version: 3.x - run: pip install zensical - run: zensical build --clean - - name: Add CNAME for custom domain - run: echo "typst-in-production.com" > site/CNAME - name: Deploy to gh-pages uses: peaceiris/actions-gh-pages@v4 diff --git a/README.md b/README.md index c3362ec..cbe94f0 100644 --- a/README.md +++ b/README.md @@ -28,3 +28,237 @@ Latest dev version: ``` pip install git+https://github.com/y-sunflower/plotjs.git ``` + +If you use `uv`: + +```bash +uv add plotjs +``` + +## Why `plotjs`? + +`plotjs` keeps your existing matplotlib workflow and adds interactivity on top of the SVG that matplotlib already knows how to generate. Instead of rebuilding the chart in another library, you keep the same `Figure`, export it to HTML, and control the browser-side behavior with CSS and JavaScript. + +## Features Overview + +- Keep your existing matplotlib figure and export it as a standalone interactive HTML file +- Add hover tooltips from any iterable of labels +- Highlight related elements together with `groups=...` +- Support scatter, line, bar, and area charts +- Restrict interactivity to specific element types with `on=...` +- Use direct hover or nearest-element hover with `hover_nearest=True` +- Add custom CSS with strings, dictionaries, or files +- Add custom JavaScript with strings or files, and optionally load D3.js +- Work with multiple matplotlib axes in the same figure +- Export either to disk with `save()` or to an HTML string with `as_html()` + +## Quickstart + +```python +import matplotlib.pyplot as plt +from plotjs import PlotJS, data + +df = data.load_iris() + +fig, ax = plt.subplots() +ax.scatter( + df["sepal_length"], + df["sepal_width"], + c=df["species"].astype("category").cat.codes, + s=180, + alpha=0.6, + ec="black", +) + +( + PlotJS(fig) + .add_tooltip(labels=df["species"]) + .save("iris-scatter.html") +) +``` + +Open `iris-scatter.html` in your browser to get hover tooltips and default highlight/fade behavior. + +## Reprex + +### 1. Group hover by category + +```python +import matplotlib.pyplot as plt +from plotjs import PlotJS, data + +df = data.load_iris() + +fig, ax = plt.subplots() +ax.scatter( + df["petal_length"], + df["petal_width"], + c=df["species"].astype("category").cat.codes, + s=180, + alpha=0.6, + ec="black", +) + +( + PlotJS(fig) + .add_tooltip( + labels=df["species"], + groups=df["species"], + ) + .save("iris-grouped.html") +) +``` + +All points from the same species will highlight together. + +### 2. Customize the tooltip and hover state with CSS + +```python +import matplotlib.pyplot as plt +from plotjs import PlotJS, data + +df = data.load_iris() +labels = df.apply( + lambda row: ( + f"{row['species']}
" + f"petal_length = {row['petal_length']}
" + f"petal_width = {row['petal_width']}" + ), + axis=1, +) + +fig, ax = plt.subplots() +ax.scatter( + df["petal_length"], + df["petal_width"], + c=df["species"].astype("category").cat.codes, + s=180, + alpha=0.6, + ec="black", +) + +( + PlotJS(fig) + .add_tooltip( + labels=labels, + groups=df["species"], + hover_nearest=True, + on="point", + ) + .add_css( + from_dict={ + ".tooltip": { + "background": "#111827", + "color": "white", + "font-size": "0.95rem", + "text-align": "center", + }, + ".point.hovered": { + "stroke": "#111827", + "stroke-width": "2px", + }, + ".point.not-hovered": { + "opacity": "0.25", + }, + } + ) + .save("iris-custom.html") +) +``` + +### 3. Add interactivity to multiple axes + +```python +import matplotlib.pyplot as plt +from plotjs import PlotJS, data + +df = data.load_iris() +colors = df["species"].astype("category").cat.codes + +fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4)) + +ax1.scatter( + df["sepal_length"], + df["sepal_width"], + c=colors, + s=120, + alpha=0.6, + ec="black", +) +ax2.scatter( + df["petal_length"], + df["petal_width"], + c=colors, + s=120, + alpha=0.6, + ec="black", +) + +( + PlotJS(fig) + .add_tooltip(labels=df["species"], groups=df["species"], ax=ax1) + .add_tooltip(labels=df["species"], groups=df["species"], ax=ax2) + .save("iris-two-axes.html") +) +``` + +### 4. Embed the chart elsewhere with `as_html()` + +```python +import matplotlib.pyplot as plt +from plotjs import PlotJS, data + +df = data.load_iris() + +fig, ax = plt.subplots() +ax.scatter(df["sepal_length"], df["sepal_width"]) + +html = ( + PlotJS(fig) + .add_tooltip(labels=df["species"]) + .as_html() +) +``` + +This is useful for environments like marimo, or for embedding the output in your own app or webpage. + +## Supported Plot Elements + +`plotjs` currently detects these matplotlib SVG elements: + +- Scatter points +- Lines +- Bars +- Filled areas + +These are also the main selectors you can target from CSS or JavaScript: + +- `.point` +- `.line` +- `.bar` +- `.area` +- `.plot-element` +- `.tooltip` +- `svg` + +## Important Limitation + +The order in which matplotlib draws elements must match the order of your `labels` and `groups`. + +If you plot data in chunks or loops, make sure the tooltip arrays follow the exact same order. When possible, plotting all elements at once is the safest option. + +## How It Works + +1. `plotjs` saves your matplotlib `Figure` as SVG. +2. It injects that SVG, your tooltip metadata, and optional CSS/JavaScript into an HTML template. +3. In the browser, JavaScript parses the SVG DOM and attaches hover effects, tooltips, and grouping behavior. + +## Documentation + +- [Getting started](docs/index.md) +- [PlotJS API reference](docs/reference/plotjs.md) +- [CSS guide](docs/guides/css/index.md) +- [JavaScript guide](docs/guides/javascript/index.md) +- [Embedding in Quarto, marimo, or websites](docs/guides/embed-graphs/index.md) +- [Troubleshooting](docs/guides/troubleshooting/index.md) +- [Developer architecture overview](docs/developers/overview.md) diff --git a/docs/developers/svg-parser-reference.md b/docs/developers/svg-parser-reference.md index 09915de..9ebc6fe 100644 --- a/docs/developers/svg-parser-reference.md +++ b/docs/developers/svg-parser-reference.md @@ -16,6 +16,9 @@ Provides basic DOM manipulation methods for working with SVG elements.

getPointerPosition(event, svgElement)Array.<number>

Get mouse position relative to an SVG element.

+
getFillValue(element)string
+

Extract the raw fill value from an SVG element.

+
findBars(svg, axes_class)Selection

Find bar elements (patch groups with clipping) inside a given axes.

@@ -29,7 +32,9 @@ and assigns data-group attributes based on tooltip groups.

excluding axis grid lines.

findAreas(svg, axes_class)Selection
-

Find filled area elements (FillBetweenPolyCollection paths) inside a given axes.

+

Find filled area elements (FillBetweenPolyCollection paths) inside a given axes. +Also includes legend swatches whose fill matches the plotted areas so legend hover +can target the same series as the chart area.

nearestElementFromMouse(mouseX, mouseY, elements)Element | null

Compute the nearest element to the mouse cursor from a set of elements. @@ -74,6 +79,18 @@ Get mouse position relative to an SVG element. | event | MouseEvent | The mouse event | | svgElement | Element \| [Selection](#Selection) | The SVG element or Selection | + + +## getFillValue(element) ⇒ string +Extract the raw fill value from an SVG element. + +**Kind**: global function +**Returns**: string - Normalized fill value, or empty string if absent. + +| Param | Type | Description | +| --- | --- | --- | +| element | Element | SVG element to inspect. | + ## findBars(svg, axes_class) ⇒ [Selection](#Selection) @@ -121,6 +138,8 @@ excluding axis grid lines. ## findAreas(svg, axes_class) ⇒ [Selection](#Selection) Find filled area elements (`FillBetweenPolyCollection` paths) inside a given axes. +Also includes legend swatches whose fill matches the plotted areas so legend hover +can target the same series as the chart area. **Kind**: global function **Returns**: [Selection](#Selection) - Selection of area elements. diff --git a/docs/iframes/CSS-2.html b/docs/iframes/CSS-2.html index 61398ab..25a5efa 100644 --- a/docs/iframes/CSS-2.html +++ b/docs/iframes/CSS-2.html @@ -65,7 +65,7 @@ - 2026-02-02T14:52:23.438279 + 2026-03-15T20:57:18.692897 image/svg+xml @@ -1518,6 +1518,23 @@ this.tooltip_y_shift = tooltip_y_shift; } + /** + * Extract the raw fill value from an SVG element. + * + * @param {Element} element - SVG element to inspect. + * @returns {string} Normalized fill value, or empty string if absent. + */ + getFillValue(element) { + const style = element?.getAttribute("style") ?? ""; + const styleMatch = style.match(/(?:^|;)\s*fill:\s*([^;]+)/i); + + if (styleMatch) { + return styleMatch[1].trim().toLowerCase(); + } + + return (element?.getAttribute("fill") ?? "").trim().toLowerCase(); + } + /** * Find bar elements (`patch` groups with clipping) inside a given axes. * @@ -1594,16 +1611,35 @@ /** * Find filled area elements (`FillBetweenPolyCollection` paths) inside a given axes. + * Also includes legend swatches whose fill matches the plotted areas so legend hover + * can target the same series as the chart area. * * @param {Selection} svg - Selection of the SVG element. * @param {string} axes_class - ID of the axes group. * @returns {Selection} Selection of area elements. */ findAreas(svg, axes_class) { - // select all of FillBetweenPolyCollection elements within the specific axes - const areas = svg.selectAll( + const parser = this; + const plottedAreas = svg.selectAll( `g#${axes_class} g[id^="FillBetweenPolyCollection"] path`, ); + const areaFills = new Set( + plottedAreas + .nodes() + .map((element) => this.getFillValue(element)) + .filter((fill) => fill && fill !== "none"), + ); + + const legendAreas = svg + .selectAll(`g#${axes_class} g[id^="legend"] g[id^="patch"] path`) + .filter(function () { + return areaFills.size > 0 && areaFills.has(parser.getFillValue(this)); + }); + + const areas = new Selection([ + ...plottedAreas.nodes(), + ...legendAreas.nodes(), + ]); areas.attr("class", "area plot-element"); console.log(`Found ${areas.size()} "area" element`); diff --git a/docs/iframes/CSS.html b/docs/iframes/CSS.html index 8c50f54..5c466a3 100644 --- a/docs/iframes/CSS.html +++ b/docs/iframes/CSS.html @@ -61,7 +61,7 @@ - 2026-02-02T14:52:23.343865 + 2026-03-15T20:57:18.640742 image/svg+xml @@ -1514,6 +1514,23 @@ this.tooltip_y_shift = tooltip_y_shift; } + /** + * Extract the raw fill value from an SVG element. + * + * @param {Element} element - SVG element to inspect. + * @returns {string} Normalized fill value, or empty string if absent. + */ + getFillValue(element) { + const style = element?.getAttribute("style") ?? ""; + const styleMatch = style.match(/(?:^|;)\s*fill:\s*([^;]+)/i); + + if (styleMatch) { + return styleMatch[1].trim().toLowerCase(); + } + + return (element?.getAttribute("fill") ?? "").trim().toLowerCase(); + } + /** * Find bar elements (`patch` groups with clipping) inside a given axes. * @@ -1590,16 +1607,35 @@ /** * Find filled area elements (`FillBetweenPolyCollection` paths) inside a given axes. + * Also includes legend swatches whose fill matches the plotted areas so legend hover + * can target the same series as the chart area. * * @param {Selection} svg - Selection of the SVG element. * @param {string} axes_class - ID of the axes group. * @returns {Selection} Selection of area elements. */ findAreas(svg, axes_class) { - // select all of FillBetweenPolyCollection elements within the specific axes - const areas = svg.selectAll( + const parser = this; + const plottedAreas = svg.selectAll( `g#${axes_class} g[id^="FillBetweenPolyCollection"] path`, ); + const areaFills = new Set( + plottedAreas + .nodes() + .map((element) => this.getFillValue(element)) + .filter((fill) => fill && fill !== "none"), + ); + + const legendAreas = svg + .selectAll(`g#${axes_class} g[id^="legend"] g[id^="patch"] path`) + .filter(function () { + return areaFills.size > 0 && areaFills.has(parser.getFillValue(this)); + }); + + const areas = new Selection([ + ...plottedAreas.nodes(), + ...legendAreas.nodes(), + ]); areas.attr("class", "area plot-element"); console.log(`Found ${areas.size()} "area" element`); diff --git a/docs/iframes/area-natural-disasters.html b/docs/iframes/area-natural-disasters.html index 0db646d..c6759e2 100644 --- a/docs/iframes/area-natural-disasters.html +++ b/docs/iframes/area-natural-disasters.html @@ -61,7 +61,7 @@ - 2026-02-02T14:52:22.386313 + 2026-03-15T20:57:17.845442 image/svg+xml @@ -3822,6 +3822,23 @@ this.tooltip_y_shift = tooltip_y_shift; } + /** + * Extract the raw fill value from an SVG element. + * + * @param {Element} element - SVG element to inspect. + * @returns {string} Normalized fill value, or empty string if absent. + */ + getFillValue(element) { + const style = element?.getAttribute("style") ?? ""; + const styleMatch = style.match(/(?:^|;)\s*fill:\s*([^;]+)/i); + + if (styleMatch) { + return styleMatch[1].trim().toLowerCase(); + } + + return (element?.getAttribute("fill") ?? "").trim().toLowerCase(); + } + /** * Find bar elements (`patch` groups with clipping) inside a given axes. * @@ -3898,16 +3915,35 @@ /** * Find filled area elements (`FillBetweenPolyCollection` paths) inside a given axes. + * Also includes legend swatches whose fill matches the plotted areas so legend hover + * can target the same series as the chart area. * * @param {Selection} svg - Selection of the SVG element. * @param {string} axes_class - ID of the axes group. * @returns {Selection} Selection of area elements. */ findAreas(svg, axes_class) { - // select all of FillBetweenPolyCollection elements within the specific axes - const areas = svg.selectAll( + const parser = this; + const plottedAreas = svg.selectAll( `g#${axes_class} g[id^="FillBetweenPolyCollection"] path`, ); + const areaFills = new Set( + plottedAreas + .nodes() + .map((element) => this.getFillValue(element)) + .filter((fill) => fill && fill !== "none"), + ); + + const legendAreas = svg + .selectAll(`g#${axes_class} g[id^="legend"] g[id^="patch"] path`) + .filter(function () { + return areaFills.size > 0 && areaFills.has(parser.getFillValue(this)); + }); + + const areas = new Selection([ + ...plottedAreas.nodes(), + ...legendAreas.nodes(), + ]); areas.attr("class", "area plot-element"); console.log(`Found ${areas.size()} "area" element`); diff --git a/docs/iframes/bug.html b/docs/iframes/bug.html index 90eddf0..65014ce 100644 --- a/docs/iframes/bug.html +++ b/docs/iframes/bug.html @@ -61,7 +61,7 @@ - 2026-02-02T14:52:20.263135 + 2026-03-15T20:57:15.050060 image/svg+xml @@ -933,6 +933,23 @@ this.tooltip_y_shift = tooltip_y_shift; } + /** + * Extract the raw fill value from an SVG element. + * + * @param {Element} element - SVG element to inspect. + * @returns {string} Normalized fill value, or empty string if absent. + */ + getFillValue(element) { + const style = element?.getAttribute("style") ?? ""; + const styleMatch = style.match(/(?:^|;)\s*fill:\s*([^;]+)/i); + + if (styleMatch) { + return styleMatch[1].trim().toLowerCase(); + } + + return (element?.getAttribute("fill") ?? "").trim().toLowerCase(); + } + /** * Find bar elements (`patch` groups with clipping) inside a given axes. * @@ -1009,16 +1026,35 @@ /** * Find filled area elements (`FillBetweenPolyCollection` paths) inside a given axes. + * Also includes legend swatches whose fill matches the plotted areas so legend hover + * can target the same series as the chart area. * * @param {Selection} svg - Selection of the SVG element. * @param {string} axes_class - ID of the axes group. * @returns {Selection} Selection of area elements. */ findAreas(svg, axes_class) { - // select all of FillBetweenPolyCollection elements within the specific axes - const areas = svg.selectAll( + const parser = this; + const plottedAreas = svg.selectAll( `g#${axes_class} g[id^="FillBetweenPolyCollection"] path`, ); + const areaFills = new Set( + plottedAreas + .nodes() + .map((element) => this.getFillValue(element)) + .filter((fill) => fill && fill !== "none"), + ); + + const legendAreas = svg + .selectAll(`g#${axes_class} g[id^="legend"] g[id^="patch"] path`) + .filter(function () { + return areaFills.size > 0 && areaFills.has(parser.getFillValue(this)); + }); + + const areas = new Selection([ + ...plottedAreas.nodes(), + ...legendAreas.nodes(), + ]); areas.attr("class", "area plot-element"); console.log(`Found ${areas.size()} "area" element`); diff --git a/docs/iframes/javascript.html b/docs/iframes/javascript.html index 323e388..93738ec 100644 --- a/docs/iframes/javascript.html +++ b/docs/iframes/javascript.html @@ -61,7 +61,7 @@ - 2026-02-02T14:52:24.191469 + 2026-03-15T20:57:19.351940 image/svg+xml @@ -1197,6 +1197,23 @@ this.tooltip_y_shift = tooltip_y_shift; } + /** + * Extract the raw fill value from an SVG element. + * + * @param {Element} element - SVG element to inspect. + * @returns {string} Normalized fill value, or empty string if absent. + */ + getFillValue(element) { + const style = element?.getAttribute("style") ?? ""; + const styleMatch = style.match(/(?:^|;)\s*fill:\s*([^;]+)/i); + + if (styleMatch) { + return styleMatch[1].trim().toLowerCase(); + } + + return (element?.getAttribute("fill") ?? "").trim().toLowerCase(); + } + /** * Find bar elements (`patch` groups with clipping) inside a given axes. * @@ -1273,16 +1290,35 @@ /** * Find filled area elements (`FillBetweenPolyCollection` paths) inside a given axes. + * Also includes legend swatches whose fill matches the plotted areas so legend hover + * can target the same series as the chart area. * * @param {Selection} svg - Selection of the SVG element. * @param {string} axes_class - ID of the axes group. * @returns {Selection} Selection of area elements. */ findAreas(svg, axes_class) { - // select all of FillBetweenPolyCollection elements within the specific axes - const areas = svg.selectAll( + const parser = this; + const plottedAreas = svg.selectAll( `g#${axes_class} g[id^="FillBetweenPolyCollection"] path`, ); + const areaFills = new Set( + plottedAreas + .nodes() + .map((element) => this.getFillValue(element)) + .filter((fill) => fill && fill !== "none"), + ); + + const legendAreas = svg + .selectAll(`g#${axes_class} g[id^="legend"] g[id^="patch"] path`) + .filter(function () { + return areaFills.size > 0 && areaFills.has(parser.getFillValue(this)); + }); + + const areas = new Selection([ + ...plottedAreas.nodes(), + ...legendAreas.nodes(), + ]); areas.attr("class", "area plot-element"); console.log(`Found ${areas.size()} "area" element`); diff --git a/docs/iframes/javascript2.html b/docs/iframes/javascript2.html index a8cc1b2..40af739 100644 --- a/docs/iframes/javascript2.html +++ b/docs/iframes/javascript2.html @@ -68,7 +68,7 @@ - 2026-02-02T14:52:24.248147 + 2026-03-15T20:57:19.393021 image/svg+xml @@ -1268,6 +1268,23 @@ this.tooltip_y_shift = tooltip_y_shift; } + /** + * Extract the raw fill value from an SVG element. + * + * @param {Element} element - SVG element to inspect. + * @returns {string} Normalized fill value, or empty string if absent. + */ + getFillValue(element) { + const style = element?.getAttribute("style") ?? ""; + const styleMatch = style.match(/(?:^|;)\s*fill:\s*([^;]+)/i); + + if (styleMatch) { + return styleMatch[1].trim().toLowerCase(); + } + + return (element?.getAttribute("fill") ?? "").trim().toLowerCase(); + } + /** * Find bar elements (`patch` groups with clipping) inside a given axes. * @@ -1344,16 +1361,35 @@ /** * Find filled area elements (`FillBetweenPolyCollection` paths) inside a given axes. + * Also includes legend swatches whose fill matches the plotted areas so legend hover + * can target the same series as the chart area. * * @param {Selection} svg - Selection of the SVG element. * @param {string} axes_class - ID of the axes group. * @returns {Selection} Selection of area elements. */ findAreas(svg, axes_class) { - // select all of FillBetweenPolyCollection elements within the specific axes - const areas = svg.selectAll( + const parser = this; + const plottedAreas = svg.selectAll( `g#${axes_class} g[id^="FillBetweenPolyCollection"] path`, ); + const areaFills = new Set( + plottedAreas + .nodes() + .map((element) => this.getFillValue(element)) + .filter((fill) => fill && fill !== "none"), + ); + + const legendAreas = svg + .selectAll(`g#${axes_class} g[id^="legend"] g[id^="patch"] path`) + .filter(function () { + return areaFills.size > 0 && areaFills.has(parser.getFillValue(this)); + }); + + const areas = new Selection([ + ...plottedAreas.nodes(), + ...legendAreas.nodes(), + ]); areas.attr("class", "area plot-element"); console.log(`Found ${areas.size()} "area" element`); diff --git a/docs/iframes/quickstart.html b/docs/iframes/quickstart.html index 81ceff7..8ae12fe 100644 --- a/docs/iframes/quickstart.html +++ b/docs/iframes/quickstart.html @@ -61,7 +61,7 @@ - 2026-02-02T14:52:18.922576 + 2026-03-15T20:57:13.886877 image/svg+xml @@ -1197,6 +1197,23 @@ this.tooltip_y_shift = tooltip_y_shift; } + /** + * Extract the raw fill value from an SVG element. + * + * @param {Element} element - SVG element to inspect. + * @returns {string} Normalized fill value, or empty string if absent. + */ + getFillValue(element) { + const style = element?.getAttribute("style") ?? ""; + const styleMatch = style.match(/(?:^|;)\s*fill:\s*([^;]+)/i); + + if (styleMatch) { + return styleMatch[1].trim().toLowerCase(); + } + + return (element?.getAttribute("fill") ?? "").trim().toLowerCase(); + } + /** * Find bar elements (`patch` groups with clipping) inside a given axes. * @@ -1273,16 +1290,35 @@ /** * Find filled area elements (`FillBetweenPolyCollection` paths) inside a given axes. + * Also includes legend swatches whose fill matches the plotted areas so legend hover + * can target the same series as the chart area. * * @param {Selection} svg - Selection of the SVG element. * @param {string} axes_class - ID of the axes group. * @returns {Selection} Selection of area elements. */ findAreas(svg, axes_class) { - // select all of FillBetweenPolyCollection elements within the specific axes - const areas = svg.selectAll( + const parser = this; + const plottedAreas = svg.selectAll( `g#${axes_class} g[id^="FillBetweenPolyCollection"] path`, ); + const areaFills = new Set( + plottedAreas + .nodes() + .map((element) => this.getFillValue(element)) + .filter((fill) => fill && fill !== "none"), + ); + + const legendAreas = svg + .selectAll(`g#${axes_class} g[id^="legend"] g[id^="patch"] path`) + .filter(function () { + return areaFills.size > 0 && areaFills.has(parser.getFillValue(this)); + }); + + const areas = new Selection([ + ...plottedAreas.nodes(), + ...legendAreas.nodes(), + ]); areas.attr("class", "area plot-element"); console.log(`Found ${areas.size()} "area" element`); diff --git a/docs/iframes/quickstart10.html b/docs/iframes/quickstart10.html index f4c033c..7860a77 100644 --- a/docs/iframes/quickstart10.html +++ b/docs/iframes/quickstart10.html @@ -61,7 +61,7 @@ - 2026-02-02T14:52:19.859810 + 2026-03-15T20:57:14.708540 image/svg+xml @@ -933,6 +933,23 @@ this.tooltip_y_shift = tooltip_y_shift; } + /** + * Extract the raw fill value from an SVG element. + * + * @param {Element} element - SVG element to inspect. + * @returns {string} Normalized fill value, or empty string if absent. + */ + getFillValue(element) { + const style = element?.getAttribute("style") ?? ""; + const styleMatch = style.match(/(?:^|;)\s*fill:\s*([^;]+)/i); + + if (styleMatch) { + return styleMatch[1].trim().toLowerCase(); + } + + return (element?.getAttribute("fill") ?? "").trim().toLowerCase(); + } + /** * Find bar elements (`patch` groups with clipping) inside a given axes. * @@ -1009,16 +1026,35 @@ /** * Find filled area elements (`FillBetweenPolyCollection` paths) inside a given axes. + * Also includes legend swatches whose fill matches the plotted areas so legend hover + * can target the same series as the chart area. * * @param {Selection} svg - Selection of the SVG element. * @param {string} axes_class - ID of the axes group. * @returns {Selection} Selection of area elements. */ findAreas(svg, axes_class) { - // select all of FillBetweenPolyCollection elements within the specific axes - const areas = svg.selectAll( + const parser = this; + const plottedAreas = svg.selectAll( `g#${axes_class} g[id^="FillBetweenPolyCollection"] path`, ); + const areaFills = new Set( + plottedAreas + .nodes() + .map((element) => this.getFillValue(element)) + .filter((fill) => fill && fill !== "none"), + ); + + const legendAreas = svg + .selectAll(`g#${axes_class} g[id^="legend"] g[id^="patch"] path`) + .filter(function () { + return areaFills.size > 0 && areaFills.has(parser.getFillValue(this)); + }); + + const areas = new Selection([ + ...plottedAreas.nodes(), + ...legendAreas.nodes(), + ]); areas.attr("class", "area plot-element"); console.log(`Found ${areas.size()} "area" element`); diff --git a/docs/iframes/quickstart11.html b/docs/iframes/quickstart11.html index f925231..4600c67 100644 --- a/docs/iframes/quickstart11.html +++ b/docs/iframes/quickstart11.html @@ -61,7 +61,7 @@ - 2026-02-02T14:52:20.009575 + 2026-03-15T20:57:14.836735 image/svg+xml @@ -2351,6 +2351,23 @@ this.tooltip_y_shift = tooltip_y_shift; } + /** + * Extract the raw fill value from an SVG element. + * + * @param {Element} element - SVG element to inspect. + * @returns {string} Normalized fill value, or empty string if absent. + */ + getFillValue(element) { + const style = element?.getAttribute("style") ?? ""; + const styleMatch = style.match(/(?:^|;)\s*fill:\s*([^;]+)/i); + + if (styleMatch) { + return styleMatch[1].trim().toLowerCase(); + } + + return (element?.getAttribute("fill") ?? "").trim().toLowerCase(); + } + /** * Find bar elements (`patch` groups with clipping) inside a given axes. * @@ -2427,16 +2444,35 @@ /** * Find filled area elements (`FillBetweenPolyCollection` paths) inside a given axes. + * Also includes legend swatches whose fill matches the plotted areas so legend hover + * can target the same series as the chart area. * * @param {Selection} svg - Selection of the SVG element. * @param {string} axes_class - ID of the axes group. * @returns {Selection} Selection of area elements. */ findAreas(svg, axes_class) { - // select all of FillBetweenPolyCollection elements within the specific axes - const areas = svg.selectAll( + const parser = this; + const plottedAreas = svg.selectAll( `g#${axes_class} g[id^="FillBetweenPolyCollection"] path`, ); + const areaFills = new Set( + plottedAreas + .nodes() + .map((element) => this.getFillValue(element)) + .filter((fill) => fill && fill !== "none"), + ); + + const legendAreas = svg + .selectAll(`g#${axes_class} g[id^="legend"] g[id^="patch"] path`) + .filter(function () { + return areaFills.size > 0 && areaFills.has(parser.getFillValue(this)); + }); + + const areas = new Selection([ + ...plottedAreas.nodes(), + ...legendAreas.nodes(), + ]); areas.attr("class", "area plot-element"); console.log(`Found ${areas.size()} "area" element`); diff --git a/docs/iframes/quickstart2.html b/docs/iframes/quickstart2.html index 248a601..166ffd4 100644 --- a/docs/iframes/quickstart2.html +++ b/docs/iframes/quickstart2.html @@ -61,7 +61,7 @@ - 2026-02-02T14:52:18.952473 + 2026-03-15T20:57:13.909929 image/svg+xml @@ -1197,6 +1197,23 @@ this.tooltip_y_shift = tooltip_y_shift; } + /** + * Extract the raw fill value from an SVG element. + * + * @param {Element} element - SVG element to inspect. + * @returns {string} Normalized fill value, or empty string if absent. + */ + getFillValue(element) { + const style = element?.getAttribute("style") ?? ""; + const styleMatch = style.match(/(?:^|;)\s*fill:\s*([^;]+)/i); + + if (styleMatch) { + return styleMatch[1].trim().toLowerCase(); + } + + return (element?.getAttribute("fill") ?? "").trim().toLowerCase(); + } + /** * Find bar elements (`patch` groups with clipping) inside a given axes. * @@ -1273,16 +1290,35 @@ /** * Find filled area elements (`FillBetweenPolyCollection` paths) inside a given axes. + * Also includes legend swatches whose fill matches the plotted areas so legend hover + * can target the same series as the chart area. * * @param {Selection} svg - Selection of the SVG element. * @param {string} axes_class - ID of the axes group. * @returns {Selection} Selection of area elements. */ findAreas(svg, axes_class) { - // select all of FillBetweenPolyCollection elements within the specific axes - const areas = svg.selectAll( + const parser = this; + const plottedAreas = svg.selectAll( `g#${axes_class} g[id^="FillBetweenPolyCollection"] path`, ); + const areaFills = new Set( + plottedAreas + .nodes() + .map((element) => this.getFillValue(element)) + .filter((fill) => fill && fill !== "none"), + ); + + const legendAreas = svg + .selectAll(`g#${axes_class} g[id^="legend"] g[id^="patch"] path`) + .filter(function () { + return areaFills.size > 0 && areaFills.has(parser.getFillValue(this)); + }); + + const areas = new Selection([ + ...plottedAreas.nodes(), + ...legendAreas.nodes(), + ]); areas.attr("class", "area plot-element"); console.log(`Found ${areas.size()} "area" element`); diff --git a/docs/iframes/quickstart3.html b/docs/iframes/quickstart3.html index e08218e..efd64bf 100644 --- a/docs/iframes/quickstart3.html +++ b/docs/iframes/quickstart3.html @@ -61,7 +61,7 @@ - 2026-02-02T14:52:18.983212 + 2026-03-15T20:57:13.929348 image/svg+xml @@ -1197,6 +1197,23 @@ this.tooltip_y_shift = tooltip_y_shift; } + /** + * Extract the raw fill value from an SVG element. + * + * @param {Element} element - SVG element to inspect. + * @returns {string} Normalized fill value, or empty string if absent. + */ + getFillValue(element) { + const style = element?.getAttribute("style") ?? ""; + const styleMatch = style.match(/(?:^|;)\s*fill:\s*([^;]+)/i); + + if (styleMatch) { + return styleMatch[1].trim().toLowerCase(); + } + + return (element?.getAttribute("fill") ?? "").trim().toLowerCase(); + } + /** * Find bar elements (`patch` groups with clipping) inside a given axes. * @@ -1273,16 +1290,35 @@ /** * Find filled area elements (`FillBetweenPolyCollection` paths) inside a given axes. + * Also includes legend swatches whose fill matches the plotted areas so legend hover + * can target the same series as the chart area. * * @param {Selection} svg - Selection of the SVG element. * @param {string} axes_class - ID of the axes group. * @returns {Selection} Selection of area elements. */ findAreas(svg, axes_class) { - // select all of FillBetweenPolyCollection elements within the specific axes - const areas = svg.selectAll( + const parser = this; + const plottedAreas = svg.selectAll( `g#${axes_class} g[id^="FillBetweenPolyCollection"] path`, ); + const areaFills = new Set( + plottedAreas + .nodes() + .map((element) => this.getFillValue(element)) + .filter((fill) => fill && fill !== "none"), + ); + + const legendAreas = svg + .selectAll(`g#${axes_class} g[id^="legend"] g[id^="patch"] path`) + .filter(function () { + return areaFills.size > 0 && areaFills.has(parser.getFillValue(this)); + }); + + const areas = new Selection([ + ...plottedAreas.nodes(), + ...legendAreas.nodes(), + ]); areas.attr("class", "area plot-element"); console.log(`Found ${areas.size()} "area" element`); diff --git a/docs/iframes/quickstart4.html b/docs/iframes/quickstart4.html index f609ae6..ac933f9 100644 --- a/docs/iframes/quickstart4.html +++ b/docs/iframes/quickstart4.html @@ -61,7 +61,7 @@ - 2026-02-02T14:52:19.019290 + 2026-03-15T20:57:13.954602 image/svg+xml @@ -1197,6 +1197,23 @@ this.tooltip_y_shift = tooltip_y_shift; } + /** + * Extract the raw fill value from an SVG element. + * + * @param {Element} element - SVG element to inspect. + * @returns {string} Normalized fill value, or empty string if absent. + */ + getFillValue(element) { + const style = element?.getAttribute("style") ?? ""; + const styleMatch = style.match(/(?:^|;)\s*fill:\s*([^;]+)/i); + + if (styleMatch) { + return styleMatch[1].trim().toLowerCase(); + } + + return (element?.getAttribute("fill") ?? "").trim().toLowerCase(); + } + /** * Find bar elements (`patch` groups with clipping) inside a given axes. * @@ -1273,16 +1290,35 @@ /** * Find filled area elements (`FillBetweenPolyCollection` paths) inside a given axes. + * Also includes legend swatches whose fill matches the plotted areas so legend hover + * can target the same series as the chart area. * * @param {Selection} svg - Selection of the SVG element. * @param {string} axes_class - ID of the axes group. * @returns {Selection} Selection of area elements. */ findAreas(svg, axes_class) { - // select all of FillBetweenPolyCollection elements within the specific axes - const areas = svg.selectAll( + const parser = this; + const plottedAreas = svg.selectAll( `g#${axes_class} g[id^="FillBetweenPolyCollection"] path`, ); + const areaFills = new Set( + plottedAreas + .nodes() + .map((element) => this.getFillValue(element)) + .filter((fill) => fill && fill !== "none"), + ); + + const legendAreas = svg + .selectAll(`g#${axes_class} g[id^="legend"] g[id^="patch"] path`) + .filter(function () { + return areaFills.size > 0 && areaFills.has(parser.getFillValue(this)); + }); + + const areas = new Selection([ + ...plottedAreas.nodes(), + ...legendAreas.nodes(), + ]); areas.attr("class", "area plot-element"); console.log(`Found ${areas.size()} "area" element`); diff --git a/docs/iframes/quickstart5.html b/docs/iframes/quickstart5.html index a6b24ab..deb522a 100644 --- a/docs/iframes/quickstart5.html +++ b/docs/iframes/quickstart5.html @@ -61,7 +61,7 @@ - 2026-02-02T14:52:19.054428 + 2026-03-15T20:57:13.979453 image/svg+xml @@ -343,12 +343,12 @@ " style="stroke: #000000; stroke-width: 0.8"/> - + - + - + - + @@ -382,12 +382,12 @@ - + - + @@ -395,12 +395,12 @@ - + - + @@ -409,813 +409,759 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + - - + @@ -1413,6 +1359,23 @@ this.tooltip_y_shift = tooltip_y_shift; } + /** + * Extract the raw fill value from an SVG element. + * + * @param {Element} element - SVG element to inspect. + * @returns {string} Normalized fill value, or empty string if absent. + */ + getFillValue(element) { + const style = element?.getAttribute("style") ?? ""; + const styleMatch = style.match(/(?:^|;)\s*fill:\s*([^;]+)/i); + + if (styleMatch) { + return styleMatch[1].trim().toLowerCase(); + } + + return (element?.getAttribute("fill") ?? "").trim().toLowerCase(); + } + /** * Find bar elements (`patch` groups with clipping) inside a given axes. * @@ -1489,16 +1452,35 @@ /** * Find filled area elements (`FillBetweenPolyCollection` paths) inside a given axes. + * Also includes legend swatches whose fill matches the plotted areas so legend hover + * can target the same series as the chart area. * * @param {Selection} svg - Selection of the SVG element. * @param {string} axes_class - ID of the axes group. * @returns {Selection} Selection of area elements. */ findAreas(svg, axes_class) { - // select all of FillBetweenPolyCollection elements within the specific axes - const areas = svg.selectAll( + const parser = this; + const plottedAreas = svg.selectAll( `g#${axes_class} g[id^="FillBetweenPolyCollection"] path`, ); + const areaFills = new Set( + plottedAreas + .nodes() + .map((element) => this.getFillValue(element)) + .filter((fill) => fill && fill !== "none"), + ); + + const legendAreas = svg + .selectAll(`g#${axes_class} g[id^="legend"] g[id^="patch"] path`) + .filter(function () { + return areaFills.size > 0 && areaFills.has(parser.getFillValue(this)); + }); + + const areas = new Selection([ + ...plottedAreas.nodes(), + ...legendAreas.nodes(), + ]); areas.attr("class", "area plot-element"); console.log(`Found ${areas.size()} "area" element`); diff --git a/docs/iframes/quickstart6.html b/docs/iframes/quickstart6.html index 846c620..bd9c5c0 100644 --- a/docs/iframes/quickstart6.html +++ b/docs/iframes/quickstart6.html @@ -61,7 +61,7 @@ - 2026-02-02T14:52:19.204102 + 2026-03-15T20:57:14.119874 image/svg+xml @@ -978,6 +978,23 @@ this.tooltip_y_shift = tooltip_y_shift; } + /** + * Extract the raw fill value from an SVG element. + * + * @param {Element} element - SVG element to inspect. + * @returns {string} Normalized fill value, or empty string if absent. + */ + getFillValue(element) { + const style = element?.getAttribute("style") ?? ""; + const styleMatch = style.match(/(?:^|;)\s*fill:\s*([^;]+)/i); + + if (styleMatch) { + return styleMatch[1].trim().toLowerCase(); + } + + return (element?.getAttribute("fill") ?? "").trim().toLowerCase(); + } + /** * Find bar elements (`patch` groups with clipping) inside a given axes. * @@ -1054,16 +1071,35 @@ /** * Find filled area elements (`FillBetweenPolyCollection` paths) inside a given axes. + * Also includes legend swatches whose fill matches the plotted areas so legend hover + * can target the same series as the chart area. * * @param {Selection} svg - Selection of the SVG element. * @param {string} axes_class - ID of the axes group. * @returns {Selection} Selection of area elements. */ findAreas(svg, axes_class) { - // select all of FillBetweenPolyCollection elements within the specific axes - const areas = svg.selectAll( + const parser = this; + const plottedAreas = svg.selectAll( `g#${axes_class} g[id^="FillBetweenPolyCollection"] path`, ); + const areaFills = new Set( + plottedAreas + .nodes() + .map((element) => this.getFillValue(element)) + .filter((fill) => fill && fill !== "none"), + ); + + const legendAreas = svg + .selectAll(`g#${axes_class} g[id^="legend"] g[id^="patch"] path`) + .filter(function () { + return areaFills.size > 0 && areaFills.has(parser.getFillValue(this)); + }); + + const areas = new Selection([ + ...plottedAreas.nodes(), + ...legendAreas.nodes(), + ]); areas.attr("class", "area plot-element"); console.log(`Found ${areas.size()} "area" element`); diff --git a/docs/iframes/quickstart7.html b/docs/iframes/quickstart7.html index 2c9d6c6..a645be7 100644 --- a/docs/iframes/quickstart7.html +++ b/docs/iframes/quickstart7.html @@ -61,7 +61,7 @@ - 2026-02-02T14:52:19.290789 + 2026-03-15T20:57:14.198616 image/svg+xml @@ -1261,6 +1261,23 @@ this.tooltip_y_shift = tooltip_y_shift; } + /** + * Extract the raw fill value from an SVG element. + * + * @param {Element} element - SVG element to inspect. + * @returns {string} Normalized fill value, or empty string if absent. + */ + getFillValue(element) { + const style = element?.getAttribute("style") ?? ""; + const styleMatch = style.match(/(?:^|;)\s*fill:\s*([^;]+)/i); + + if (styleMatch) { + return styleMatch[1].trim().toLowerCase(); + } + + return (element?.getAttribute("fill") ?? "").trim().toLowerCase(); + } + /** * Find bar elements (`patch` groups with clipping) inside a given axes. * @@ -1337,16 +1354,35 @@ /** * Find filled area elements (`FillBetweenPolyCollection` paths) inside a given axes. + * Also includes legend swatches whose fill matches the plotted areas so legend hover + * can target the same series as the chart area. * * @param {Selection} svg - Selection of the SVG element. * @param {string} axes_class - ID of the axes group. * @returns {Selection} Selection of area elements. */ findAreas(svg, axes_class) { - // select all of FillBetweenPolyCollection elements within the specific axes - const areas = svg.selectAll( + const parser = this; + const plottedAreas = svg.selectAll( `g#${axes_class} g[id^="FillBetweenPolyCollection"] path`, ); + const areaFills = new Set( + plottedAreas + .nodes() + .map((element) => this.getFillValue(element)) + .filter((fill) => fill && fill !== "none"), + ); + + const legendAreas = svg + .selectAll(`g#${axes_class} g[id^="legend"] g[id^="patch"] path`) + .filter(function () { + return areaFills.size > 0 && areaFills.has(parser.getFillValue(this)); + }); + + const areas = new Selection([ + ...plottedAreas.nodes(), + ...legendAreas.nodes(), + ]); areas.attr("class", "area plot-element"); console.log(`Found ${areas.size()} "area" element`); diff --git a/docs/iframes/quickstart8.html b/docs/iframes/quickstart8.html index 8be08ba..535bce9 100644 --- a/docs/iframes/quickstart8.html +++ b/docs/iframes/quickstart8.html @@ -61,7 +61,7 @@ - 2026-02-02T14:52:19.456197 + 2026-03-15T20:57:14.344118 image/svg+xml @@ -1721,6 +1721,23 @@ this.tooltip_y_shift = tooltip_y_shift; } + /** + * Extract the raw fill value from an SVG element. + * + * @param {Element} element - SVG element to inspect. + * @returns {string} Normalized fill value, or empty string if absent. + */ + getFillValue(element) { + const style = element?.getAttribute("style") ?? ""; + const styleMatch = style.match(/(?:^|;)\s*fill:\s*([^;]+)/i); + + if (styleMatch) { + return styleMatch[1].trim().toLowerCase(); + } + + return (element?.getAttribute("fill") ?? "").trim().toLowerCase(); + } + /** * Find bar elements (`patch` groups with clipping) inside a given axes. * @@ -1797,16 +1814,35 @@ /** * Find filled area elements (`FillBetweenPolyCollection` paths) inside a given axes. + * Also includes legend swatches whose fill matches the plotted areas so legend hover + * can target the same series as the chart area. * * @param {Selection} svg - Selection of the SVG element. * @param {string} axes_class - ID of the axes group. * @returns {Selection} Selection of area elements. */ findAreas(svg, axes_class) { - // select all of FillBetweenPolyCollection elements within the specific axes - const areas = svg.selectAll( + const parser = this; + const plottedAreas = svg.selectAll( `g#${axes_class} g[id^="FillBetweenPolyCollection"] path`, ); + const areaFills = new Set( + plottedAreas + .nodes() + .map((element) => this.getFillValue(element)) + .filter((fill) => fill && fill !== "none"), + ); + + const legendAreas = svg + .selectAll(`g#${axes_class} g[id^="legend"] g[id^="patch"] path`) + .filter(function () { + return areaFills.size > 0 && areaFills.has(parser.getFillValue(this)); + }); + + const areas = new Selection([ + ...plottedAreas.nodes(), + ...legendAreas.nodes(), + ]); areas.attr("class", "area plot-element"); console.log(`Found ${areas.size()} "area" element`); diff --git a/docs/iframes/quickstart9.html b/docs/iframes/quickstart9.html index 82020a6..1d85252 100644 --- a/docs/iframes/quickstart9.html +++ b/docs/iframes/quickstart9.html @@ -61,7 +61,7 @@ - 2026-02-02T14:52:19.622193 + 2026-03-15T20:57:14.503003 image/svg+xml @@ -1896,6 +1896,23 @@ this.tooltip_y_shift = tooltip_y_shift; } + /** + * Extract the raw fill value from an SVG element. + * + * @param {Element} element - SVG element to inspect. + * @returns {string} Normalized fill value, or empty string if absent. + */ + getFillValue(element) { + const style = element?.getAttribute("style") ?? ""; + const styleMatch = style.match(/(?:^|;)\s*fill:\s*([^;]+)/i); + + if (styleMatch) { + return styleMatch[1].trim().toLowerCase(); + } + + return (element?.getAttribute("fill") ?? "").trim().toLowerCase(); + } + /** * Find bar elements (`patch` groups with clipping) inside a given axes. * @@ -1972,16 +1989,35 @@ /** * Find filled area elements (`FillBetweenPolyCollection` paths) inside a given axes. + * Also includes legend swatches whose fill matches the plotted areas so legend hover + * can target the same series as the chart area. * * @param {Selection} svg - Selection of the SVG element. * @param {string} axes_class - ID of the axes group. * @returns {Selection} Selection of area elements. */ findAreas(svg, axes_class) { - // select all of FillBetweenPolyCollection elements within the specific axes - const areas = svg.selectAll( + const parser = this; + const plottedAreas = svg.selectAll( `g#${axes_class} g[id^="FillBetweenPolyCollection"] path`, ); + const areaFills = new Set( + plottedAreas + .nodes() + .map((element) => this.getFillValue(element)) + .filter((fill) => fill && fill !== "none"), + ); + + const legendAreas = svg + .selectAll(`g#${axes_class} g[id^="legend"] g[id^="patch"] path`) + .filter(function () { + return areaFills.size > 0 && areaFills.has(parser.getFillValue(this)); + }); + + const areas = new Selection([ + ...plottedAreas.nodes(), + ...legendAreas.nodes(), + ]); areas.attr("class", "area plot-element"); console.log(`Found ${areas.size()} "area" element`); diff --git a/docs/iframes/random-walk-1.html b/docs/iframes/random-walk-1.html index 1f3a181..e82f213 100644 --- a/docs/iframes/random-walk-1.html +++ b/docs/iframes/random-walk-1.html @@ -61,7 +61,7 @@ - 2026-02-02T14:52:22.497753 + 2026-03-15T20:57:17.902450 image/svg+xml @@ -361,12 +361,12 @@ " style="stroke: #000000; stroke-width: 0.8"/> - + - - + + + - + @@ -386,18998 +411,18770 @@ - + - - - + + + + + + - + - - - - - + + + + + - + - - - - - + + + - + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - - + - - + - - + - - + @@ -19414,13 +19211,13 @@ z " style="fill: #ffffff; opacity: 0.8; stroke: #cccccc; stroke-linejoin: miter"/> - + - + @@ -19515,31 +19312,6 @@ L 628 0 L 628 4666 z -" transform="scale(0.015625)"/> - @@ -19550,13 +19322,13 @@ - + - + @@ -19605,13 +19377,13 @@ - + - + @@ -19752,13 +19524,13 @@ - + - + @@ -19835,13 +19607,13 @@ - + - + @@ -19970,12 +19742,12 @@ - + - + @@ -19983,12 +19755,12 @@ - + - + @@ -19999,12 +19771,12 @@ - + - + @@ -20015,12 +19787,12 @@ - + - + @@ -20031,12 +19803,12 @@ - + - + @@ -20047,12 +19819,12 @@ - + - + @@ -20065,18917 +19837,18718 @@ - - + + - + - - - + + + - + - - + + - + - - - + + + - + + - - + + - + - + - + - - + + - + - - - - + + + + + - - + + - + - - - - + + + + - - + - - + - - + - - + - - + @@ -39000,27 +38573,27 @@ - - - + - + - + @@ -39029,15 +38602,15 @@ - - + - + - + @@ -39045,15 +38618,15 @@ - - + - + - + @@ -39063,15 +38636,15 @@ - - + - + - + @@ -39082,15 +38655,15 @@ - - + - + - + @@ -39279,6 +38852,23 @@ this.tooltip_y_shift = tooltip_y_shift; } + /** + * Extract the raw fill value from an SVG element. + * + * @param {Element} element - SVG element to inspect. + * @returns {string} Normalized fill value, or empty string if absent. + */ + getFillValue(element) { + const style = element?.getAttribute("style") ?? ""; + const styleMatch = style.match(/(?:^|;)\s*fill:\s*([^;]+)/i); + + if (styleMatch) { + return styleMatch[1].trim().toLowerCase(); + } + + return (element?.getAttribute("fill") ?? "").trim().toLowerCase(); + } + /** * Find bar elements (`patch` groups with clipping) inside a given axes. * @@ -39355,16 +38945,35 @@ /** * Find filled area elements (`FillBetweenPolyCollection` paths) inside a given axes. + * Also includes legend swatches whose fill matches the plotted areas so legend hover + * can target the same series as the chart area. * * @param {Selection} svg - Selection of the SVG element. * @param {string} axes_class - ID of the axes group. * @returns {Selection} Selection of area elements. */ findAreas(svg, axes_class) { - // select all of FillBetweenPolyCollection elements within the specific axes - const areas = svg.selectAll( + const parser = this; + const plottedAreas = svg.selectAll( `g#${axes_class} g[id^="FillBetweenPolyCollection"] path`, ); + const areaFills = new Set( + plottedAreas + .nodes() + .map((element) => this.getFillValue(element)) + .filter((fill) => fill && fill !== "none"), + ); + + const legendAreas = svg + .selectAll(`g#${axes_class} g[id^="legend"] g[id^="patch"] path`) + .filter(function () { + return areaFills.size > 0 && areaFills.has(parser.getFillValue(this)); + }); + + const areas = new Selection([ + ...plottedAreas.nodes(), + ...legendAreas.nodes(), + ]); areas.attr("class", "area plot-element"); console.log(`Found ${areas.size()} "area" element`); diff --git a/plotjs/plotjs.py b/plotjs/plotjs.py index 2b97426..0d105dc 100644 --- a/plotjs/plotjs.py +++ b/plotjs/plotjs.py @@ -21,11 +21,11 @@ TEMPLATE_DIR: str = MAIN_DIR / "static" CSS_PATH: str = os.path.join(TEMPLATE_DIR, "default.css") JS_PARSER_PATH: str = os.path.join(TEMPLATE_DIR, "plotparser.js") - -env: Environment = Environment(loader=FileSystemLoader(TEMPLATE_DIR)) DEFAULT_FAVICON_PATH = "https://github.com/JosephBARBIERDARNAL/static/blob/main/python-libs/plotjs/favicon.ico?raw=true" DEFAULT_DOCUMENT_TITLE = "Made with plotjs" +env: Environment = Environment(loader=FileSystemLoader(TEMPLATE_DIR)) + class PlotJS: """ @@ -35,6 +35,7 @@ class PlotJS: def __init__( self, fig: Figure | None = None, + _debug: bool = False, **savefig_kws: dict, ): """ @@ -57,6 +58,9 @@ def __init__( plt.rcParams["svg.hashsalt"] = "svg-hashsalt" plt.rcParams["svg.id"] = "svg-id" fig.savefig(buf, format="svg", **savefig_kws) + + if _debug: + fig.savefig("debug-plotjs.svg", **savefig_kws) finally: plt.rcParams["svg.hashsalt"] = old_svg_hashsalt plt.rcParams["svg.id"] = old_svg_id diff --git a/plotjs/static/plotparser.js b/plotjs/static/plotparser.js index 9fe96f8..0502872 100755 --- a/plotjs/static/plotparser.js +++ b/plotjs/static/plotparser.js @@ -160,6 +160,23 @@ export default class PlotSVGParser { this.tooltip_y_shift = tooltip_y_shift; } + /** + * Extract the raw fill value from an SVG element. + * + * @param {Element} element - SVG element to inspect. + * @returns {string} Normalized fill value, or empty string if absent. + */ + getFillValue(element) { + const style = element?.getAttribute("style") ?? ""; + const styleMatch = style.match(/(?:^|;)\s*fill:\s*([^;]+)/i); + + if (styleMatch) { + return styleMatch[1].trim().toLowerCase(); + } + + return (element?.getAttribute("fill") ?? "").trim().toLowerCase(); + } + /** * Find bar elements (`patch` groups with clipping) inside a given axes. * @@ -236,16 +253,35 @@ export default class PlotSVGParser { /** * Find filled area elements (`FillBetweenPolyCollection` paths) inside a given axes. + * Also includes legend swatches whose fill matches the plotted areas so legend hover + * can target the same series as the chart area. * * @param {Selection} svg - Selection of the SVG element. * @param {string} axes_class - ID of the axes group. * @returns {Selection} Selection of area elements. */ findAreas(svg, axes_class) { - // select all of FillBetweenPolyCollection elements within the specific axes - const areas = svg.selectAll( + const parser = this; + const plottedAreas = svg.selectAll( `g#${axes_class} g[id^="FillBetweenPolyCollection"] path`, ); + const areaFills = new Set( + plottedAreas + .nodes() + .map((element) => this.getFillValue(element)) + .filter((fill) => fill && fill !== "none"), + ); + + const legendAreas = svg + .selectAll(`g#${axes_class} g[id^="legend"] g[id^="patch"] path`) + .filter(function () { + return areaFills.size > 0 && areaFills.has(parser.getFillValue(this)); + }); + + const areas = new Selection([ + ...plottedAreas.nodes(), + ...legendAreas.nodes(), + ]); areas.attr("class", "area plot-element"); console.log(`Found ${areas.size()} "area" element`); diff --git a/tests/test-browser/test_interactions.py b/tests/test-browser/test_interactions.py index cc9fad6..c7dff4b 100644 --- a/tests/test-browser/test_interactions.py +++ b/tests/test-browser/test_interactions.py @@ -254,6 +254,51 @@ def test_line_chart_hover(page, tmp_output_dir, load_html): assert len(line_paths) > 0, "Should have at least one line path" +def test_area_legend_hover_highlights_matching_area(page, tmp_output_dir, load_html): + """Test that hovering an area legend swatch highlights the matching filled area.""" + import numpy as np + + x = np.arange(4) + y1 = np.array([2, 3, 2, 4]) + y2 = np.array([1, 1.5, 1, 2]) + + fig, ax = plt.subplots() + ax.fill_between(x, y1, label="Series A") + ax.fill_between(x, y2, label="Series B") + ax.legend() + + html_path = tmp_output_dir / "area_legend_hover.html" + PlotJS(fig).add_tooltip( + labels=["Series A", "Series B"], + groups=["Series A", "Series B"], + on="area", + ).save(str(html_path)) + plt.close(fig) + + load_html(page, html_path) + + areas = page.locator('svg g[id^="FillBetweenPolyCollection"] path.plot-element') + legend_swatches = page.locator( + 'svg g[id^="legend"] g[id^="patch"] path.plot-element' + ) + + assert areas.count() == 2, f"Expected 2 plotted areas, got {areas.count()}" + assert legend_swatches.count() == 2, ( + f"Expected 2 interactive legend swatches, got {legend_swatches.count()}" + ) + + legend_swatches.nth(0).hover(force=True) + page.wait_for_timeout(200) + + first_area_classes = areas.nth(0).get_attribute("class") or "" + second_area_classes = areas.nth(1).get_attribute("class") or "" + assert "hovered" in first_area_classes, first_area_classes + assert "not-hovered" in second_area_classes, second_area_classes + + tooltip = page.locator(".tooltip") + assert "Series A" in tooltip.inner_text() + + def test_multiple_axes_independent_hover(page, tmp_output_dir, load_html): """Test that multiple axes have independent hover interactions.""" df = data.load_iris().head(6) diff --git a/tests/test-javascript/ParserSelectors.test.js b/tests/test-javascript/ParserSelectors.test.js index 91b8399..85e2050 100644 --- a/tests/test-javascript/ParserSelectors.test.js +++ b/tests/test-javascript/ParserSelectors.test.js @@ -347,6 +347,42 @@ describe("findAreas", () => { expect(parser.findAreas(parser.svg, "axes_1").size()).toBe(1); expect(parser.findAreas(parser.svg, "axes_2").size()).toBe(1); }); + + test("should include matching legend swatches and exclude legend background", () => { + const dom = new JSDOM(` + + + + + + + + + + + + + + + + + + + + `); + + const svg = dom.window.document.querySelector("svg"); + const parser = new PlotSVGParser(svg, null, 0, 0); + const areas = parser.findAreas(parser.svg, "axes_1"); + + expect(areas.size()).toBe(4); + expect(areas.nodes().map((node) => node.parentNode.id)).toEqual([ + "FillBetweenPolyCollection_1", + "FillBetweenPolyCollection_2", + "patch_6", + "patch_7", + ]); + }); }); describe("nearestElementFromMouse", () => { diff --git a/tests/test-javascript/ParserSetHover.test.js b/tests/test-javascript/ParserSetHover.test.js index 134aad7..25aac2b 100644 --- a/tests/test-javascript/ParserSetHover.test.js +++ b/tests/test-javascript/ParserSetHover.test.js @@ -344,6 +344,65 @@ describe("setHoverEffect", () => { expect(tooltip.innerHTML).toBe("Area 1"); }); + test("should link legend swatches to grouped area elements", () => { + const dom = new JSDOM(` +

+ + + + + + + + + + + + + + + + + + + + + + `); + + const document = dom.window.document; + const svg = document.querySelector("svg"); + const tooltip = document.querySelector("#tooltip"); + const parser = new PlotSVGParser(svg, tooltip, 0, 0); + + const areas = parser.findAreas(parser.svg, "axes_1"); + parser.setHoverEffect( + areas, + "axes_1", + ["Series A", "Series B", "Series A", "Series B"], + ["Series A", "Series B", "Series A", "Series B"], + "block", + false, + ); + + const nodes = areas.nodes(); + const firstLegendSwatch = nodes[2]; + firstLegendSwatch.dispatchEvent( + new dom.window.MouseEvent("mouseover", { + bubbles: true, + pageX: 0, + pageY: 0, + currentTarget: firstLegendSwatch, + }), + ); + + expect(nodes[0].classList.contains("hovered")).toBe(true); + expect(nodes[2].classList.contains("hovered")).toBe(true); + expect(nodes[1].classList.contains("not-hovered")).toBe(true); + expect(nodes[3].classList.contains("not-hovered")).toBe(true); + expect(tooltip.innerHTML).toBe("Series A"); + }); + test("should show correct label for each element", () => { const dom = new JSDOM(` From d53f2b72d2817daab30d4512d0585a8726f6b3d6 Mon Sep 17 00:00:00 2001 From: Barbier--Darnal Joseph Date: Sun, 15 Mar 2026 21:11:03 +0100 Subject: [PATCH 5/5] update readme --- README.md | 228 +++++--------------------------- docs/img/quick-start-readme.png | Bin 0 -> 137952 bytes 2 files changed, 31 insertions(+), 197 deletions(-) create mode 100644 docs/img/quick-start-readme.png diff --git a/README.md b/README.md index cbe94f0..a413584 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,15 @@ plotjs logo -`plotjs` is a Python package that transform matplotlib plots into interactive charts with minimum user inputs. You can: +`plotjs` is a Python package that transform matplotlib plots into interactive charts with minimum user inputs. It's very easy to use and highly extensible! It lets you: - control tooltip labels and grouping - add CSS - add JavaScript - and many more -> Consider that the project is still **very unstable**. +> [!IMPORTANT] +> Consider that the project is still **unstable**. [Online demo](https://y-sunflower.github.io/plotjs/) @@ -29,31 +30,12 @@ Latest dev version: pip install git+https://github.com/y-sunflower/plotjs.git ``` -If you use `uv`: - -```bash -uv add plotjs -``` - -## Why `plotjs`? - -`plotjs` keeps your existing matplotlib workflow and adds interactivity on top of the SVG that matplotlib already knows how to generate. Instead of rebuilding the chart in another library, you keep the same `Figure`, export it to HTML, and control the browser-side behavior with CSS and JavaScript. - -## Features Overview - -- Keep your existing matplotlib figure and export it as a standalone interactive HTML file -- Add hover tooltips from any iterable of labels -- Highlight related elements together with `groups=...` -- Support scatter, line, bar, and area charts -- Restrict interactivity to specific element types with `on=...` -- Use direct hover or nearest-element hover with `hover_nearest=True` -- Add custom CSS with strings, dictionaries, or files -- Add custom JavaScript with strings or files, and optionally load D3.js -- Work with multiple matplotlib axes in the same figure -- Export either to disk with `save()` or to an HTML string with `as_html()` +
## Quickstart +`plotjs` mainly provides a `PlotJS` class + ```python import matplotlib.pyplot as plt from plotjs import PlotJS, data @@ -77,188 +59,40 @@ ax.scatter( ) ``` -Open `iris-scatter.html` in your browser to get hover tooltips and default highlight/fade behavior. - -## Reprex - -### 1. Group hover by category - -```python -import matplotlib.pyplot as plt -from plotjs import PlotJS, data - -df = data.load_iris() - -fig, ax = plt.subplots() -ax.scatter( - df["petal_length"], - df["petal_width"], - c=df["species"].astype("category").cat.codes, - s=180, - alpha=0.6, - ec="black", -) - -( - PlotJS(fig) - .add_tooltip( - labels=df["species"], - groups=df["species"], - ) - .save("iris-grouped.html") -) -``` - -All points from the same species will highlight together. - -### 2. Customize the tooltip and hover state with CSS - -```python -import matplotlib.pyplot as plt -from plotjs import PlotJS, data - -df = data.load_iris() -labels = df.apply( - lambda row: ( - f"{row['species']}
" - f"petal_length = {row['petal_length']}
" - f"petal_width = {row['petal_width']}" - ), - axis=1, -) - -fig, ax = plt.subplots() -ax.scatter( - df["petal_length"], - df["petal_width"], - c=df["species"].astype("category").cat.codes, - s=180, - alpha=0.6, - ec="black", -) - -( - PlotJS(fig) - .add_tooltip( - labels=labels, - groups=df["species"], - hover_nearest=True, - on="point", - ) - .add_css( - from_dict={ - ".tooltip": { - "background": "#111827", - "color": "white", - "font-size": "0.95rem", - "text-align": "center", - }, - ".point.hovered": { - "stroke": "#111827", - "stroke-width": "2px", - }, - ".point.not-hovered": { - "opacity": "0.25", - }, - } - ) - .save("iris-custom.html") -) -``` - -### 3. Add interactivity to multiple axes - -```python -import matplotlib.pyplot as plt -from plotjs import PlotJS, data - -df = data.load_iris() -colors = df["species"].astype("category").cat.codes - -fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4)) - -ax1.scatter( - df["sepal_length"], - df["sepal_width"], - c=colors, - s=120, - alpha=0.6, - ec="black", -) -ax2.scatter( - df["petal_length"], - df["petal_width"], - c=colors, - s=120, - alpha=0.6, - ec="black", -) - -( - PlotJS(fig) - .add_tooltip(labels=df["species"], groups=df["species"], ax=ax1) - .add_tooltip(labels=df["species"], groups=df["species"], ax=ax2) - .save("iris-two-axes.html") -) -``` - -### 4. Embed the chart elsewhere with `as_html()` +![](./docs/img/quick-start-readme.png) -```python -import matplotlib.pyplot as plt -from plotjs import PlotJS, data - -df = data.load_iris() - -fig, ax = plt.subplots() -ax.scatter(df["sepal_length"], df["sepal_width"]) - -html = ( - PlotJS(fig) - .add_tooltip(labels=df["species"]) - .as_html() -) -``` - -This is useful for environments like marimo, or for embedding the output in your own app or webpage. - -## Supported Plot Elements - -`plotjs` currently detects these matplotlib SVG elements: +Open `iris-scatter.html` in your browser to get hover tooltips and default highlight/fade behavior. -- Scatter points -- Lines -- Bars -- Filled areas +
-These are also the main selectors you can target from CSS or JavaScript: +## Why `plotjs`? -- `.point` -- `.line` -- `.bar` -- `.area` -- `.plot-element` -- `.tooltip` -- `svg` +`plotjs` keeps your existing matplotlib workflow and adds interactivity on top of the SVG that matplotlib already knows how to generate. Instead of rebuilding the chart in another library, you keep the same `Figure`, export it to HTML, and control the browser-side behavior with CSS and JavaScript. -## Important Limitation +Learn more in the [Q&A](https://y-sunflower.github.io/plotjs/#qa). -The order in which matplotlib draws elements must match the order of your `labels` and `groups`. +
-If you plot data in chunks or loops, make sure the tooltip arrays follow the exact same order. When possible, plotting all elements at once is the safest option. +## Features Overview -## How It Works +- Keep your existing matplotlib figure and export it as a standalone interactive HTML file +- Add hover tooltips from any iterable of labels +- Highlight related elements together with `groups=...` +- Restrict interactivity to specific element types with `on=...` +- Use direct hover or nearest-element hover with `hover_nearest=True` +- Add custom CSS with strings, dictionaries, or files +- Add custom JavaScript with strings or files, and optionally load D3.js +- Work with multiple matplotlib axes in the same figure +- Export either to disk with `save()` or to an HTML string with `as_html()` -1. `plotjs` saves your matplotlib `Figure` as SVG. -2. It injects that SVG, your tooltip metadata, and optional CSS/JavaScript into an HTML template. -3. In the browser, JavaScript parses the SVG DOM and attaches hover effects, tooltips, and grouping behavior. +
## Documentation -- [Getting started](docs/index.md) -- [PlotJS API reference](docs/reference/plotjs.md) -- [CSS guide](docs/guides/css/index.md) -- [JavaScript guide](docs/guides/javascript/index.md) -- [Embedding in Quarto, marimo, or websites](docs/guides/embed-graphs/index.md) -- [Troubleshooting](docs/guides/troubleshooting/index.md) -- [Developer architecture overview](docs/developers/overview.md) +- [Getting started](https://y-sunflower.github.io/plotjs/) +- [PlotJS API reference](https://y-sunflower.github.io/plotjs/reference/plotjs) +- [CSS guide](https://y-sunflower.github.io/plotjs/guides/css/) +- [JavaScript guide](https://y-sunflower.github.io/plotjs/guides/javascript/) +- [Embedding in Quarto, marimo, or websites](https://y-sunflower.github.io/plotjs/guides/embed-graphs/) +- [Troubleshooting](https://y-sunflower.github.io/plotjs/guides/troubleshooting/) +- [Developer architecture overview](https://y-sunflower.github.io/plotjs/developers/overview) diff --git a/docs/img/quick-start-readme.png b/docs/img/quick-start-readme.png new file mode 100644 index 0000000000000000000000000000000000000000..361e6ef368bdaa1bcdd88ad9130e30b3a108258c GIT binary patch literal 137952 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 F{{uJeViy1a literal 0 HcmV?d00001