plotly-print 0.2.2__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. plotly_print-0.2.2/.cursor/rules/markdown.mdc → plotly_print-0.3.0/.agents/skills/markdown/SKILL.md +5 -4
  2. plotly_print-0.3.0/.agents/skills/project-standards/SKILL.md +52 -0
  3. plotly_print-0.3.0/.gitignore +36 -0
  4. plotly_print-0.3.0/AGENTS.md +24 -0
  5. {plotly_print-0.2.2 → plotly_print-0.3.0}/PKG-INFO +20 -1
  6. {plotly_print-0.2.2 → plotly_print-0.3.0}/README.md +19 -0
  7. plotly_print-0.3.0/THIRD_PARTY_NOTICES.md +154 -0
  8. {plotly_print-0.2.2 → plotly_print-0.3.0}/pyproject.toml +7 -2
  9. plotly_print-0.3.0/src/plotly_print/AGENTS.md +30 -0
  10. plotly_print-0.3.0/src/plotly_print/_fonts/DejaVu-LICENSE.txt +98 -0
  11. plotly_print-0.3.0/src/plotly_print/_fonts/DejaVuSans-Bold.ttf +0 -0
  12. plotly_print-0.3.0/src/plotly_print/_fonts/DejaVuSans.ttf +0 -0
  13. plotly_print-0.3.0/src/plotly_print/_fonts/DejaVuSansMono.ttf +0 -0
  14. plotly_print-0.3.0/src/plotly_print/_fonts/DejaVuSerif.ttf +0 -0
  15. {plotly_print-0.2.2 → plotly_print-0.3.0}/src/plotly_print/core.py +27 -7
  16. {plotly_print-0.2.2 → plotly_print-0.3.0}/src/plotly_print/engine.py +83 -8
  17. {plotly_print-0.2.2 → plotly_print-0.3.0}/src/plotly_print/fonts.py +75 -13
  18. plotly_print-0.2.2/.cursor/rules/javascript.mdc → plotly_print-0.3.0/src/plotly_print/js/AGENTS.md +2 -7
  19. {plotly_print-0.2.2 → plotly_print-0.3.0}/src/plotly_print/plotly_hook.py +9 -0
  20. {plotly_print-0.2.2 → plotly_print-0.3.0}/src/plotly_print/raster.py +68 -10
  21. plotly_print-0.3.0/tests/AGENTS.md +6 -0
  22. plotly_print-0.3.0/tests/test_fonts.py +112 -0
  23. {plotly_print-0.2.2 → plotly_print-0.3.0}/tests/test_json_types.py +58 -0
  24. {plotly_print-0.2.2 → plotly_print-0.3.0}/uv.lock +26 -1
  25. plotly_print-0.2.2/.cursor/rules/artifacts.mdc +0 -14
  26. plotly_print-0.2.2/.cursor/rules/global.mdc +0 -72
  27. plotly_print-0.2.2/.gitignore +0 -23
  28. plotly_print-0.2.2/AGENTS.md +0 -15
  29. plotly_print-0.2.2/THIRD_PARTY_NOTICES.md +0 -40
  30. {plotly_print-0.2.2 → plotly_print-0.3.0}/.github/workflows/check-tag.yml +0 -0
  31. {plotly_print-0.2.2 → plotly_print-0.3.0}/.github/workflows/publish.yml +0 -0
  32. {plotly_print-0.2.2 → plotly_print-0.3.0}/.github/workflows/quality-checks.yml +0 -0
  33. {plotly_print-0.2.2 → plotly_print-0.3.0}/.github/workflows/version-check.yml +0 -0
  34. {plotly_print-0.2.2 → plotly_print-0.3.0}/.mdformat.toml +0 -0
  35. {plotly_print-0.2.2 → plotly_print-0.3.0}/.pre-commit-config.yaml +0 -0
  36. {plotly_print-0.2.2 → plotly_print-0.3.0}/CONTRIBUTING.md +0 -0
  37. {plotly_print-0.2.2 → plotly_print-0.3.0}/LICENSE +0 -0
  38. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/benchmark_summary.json +0 -0
  39. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_annotations_arrowheads.png +0 -0
  40. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_annotations_long_arrows.png +0 -0
  41. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_bar.png +0 -0
  42. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_barpolar.png +0 -0
  43. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_box.png +0 -0
  44. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_candlestick.png +0 -0
  45. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_carpet.png +0 -0
  46. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_contour.png +0 -0
  47. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_funnel.png +0 -0
  48. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_funnelarea.png +0 -0
  49. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_heatmap.png +0 -0
  50. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_histogram.png +0 -0
  51. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_histogram2d.png +0 -0
  52. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_icicle.png +0 -0
  53. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_indicator.png +0 -0
  54. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_ohlc.png +0 -0
  55. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_parcats.png +0 -0
  56. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_pie.png +0 -0
  57. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_rotated_ticks_45.png +0 -0
  58. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_rotated_ticks_90.png +0 -0
  59. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_sankey.png +0 -0
  60. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_scatter_line.png +0 -0
  61. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_scatterpolar.png +0 -0
  62. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_scatterternary.png +0 -0
  63. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_sunburst.png +0 -0
  64. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_table.png +0 -0
  65. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_table_markup.png +0 -0
  66. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_treemap.png +0 -0
  67. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_violin.png +0 -0
  68. {plotly_print-0.2.2 → plotly_print-0.3.0}/assets/benchmarks/compare_waterfall.png +0 -0
  69. {plotly_print-0.2.2 → plotly_print-0.3.0}/benchmark/__init__.py +0 -0
  70. {plotly_print-0.2.2 → plotly_print-0.3.0}/benchmark/__main__.py +0 -0
  71. {plotly_print-0.2.2 → plotly_print-0.3.0}/benchmark/cases.py +0 -0
  72. {plotly_print-0.2.2 → plotly_print-0.3.0}/benchmark/collage.py +0 -0
  73. {plotly_print-0.2.2 → plotly_print-0.3.0}/benchmark/compare.py +0 -0
  74. {plotly_print-0.2.2 → plotly_print-0.3.0}/benchmark/report.py +0 -0
  75. {plotly_print-0.2.2 → plotly_print-0.3.0}/benchmark/runner.py +0 -0
  76. {plotly_print-0.2.2 → plotly_print-0.3.0}/src/plotly_print/__init__.py +0 -0
  77. {plotly_print-0.2.2 → plotly_print-0.3.0}/src/plotly_print/js/micro_dom.js +0 -0
  78. {plotly_print-0.2.2 → plotly_print-0.3.0}/src/plotly_print/js/plotly_comprehensive_2d.js +0 -0
  79. {plotly_print-0.2.2 → plotly_print-0.3.0}/tests/test_background.py +0 -0
  80. {plotly_print-0.2.2 → plotly_print-0.3.0}/tests/test_bar.py +0 -0
  81. {plotly_print-0.2.2 → plotly_print-0.3.0}/tests/test_cartesian_types.py +0 -0
  82. {plotly_print-0.2.2 → plotly_print-0.3.0}/tests/test_comprehensive_2d.py +0 -0
  83. {plotly_print-0.2.2 → plotly_print-0.3.0}/tests/test_heatmap.py +0 -0
  84. {plotly_print-0.2.2 → plotly_print-0.3.0}/tests/test_kaleido_visual.py +0 -0
  85. {plotly_print-0.2.2 → plotly_print-0.3.0}/tests/test_legend.py +0 -0
  86. {plotly_print-0.2.2 → plotly_print-0.3.0}/tests/test_pie.py +0 -0
  87. {plotly_print-0.2.2 → plotly_print-0.3.0}/tests/test_plotly_hook.py +0 -0
  88. {plotly_print-0.2.2 → plotly_print-0.3.0}/tests/test_raster.py +0 -0
  89. {plotly_print-0.2.2 → plotly_print-0.3.0}/tests/test_scatter.py +0 -0
  90. {plotly_print-0.2.2 → plotly_print-0.3.0}/tests/test_svg_path_geometry.py +0 -0
  91. {plotly_print-0.2.2 → plotly_print-0.3.0}/tests/test_svg_transforms.py +0 -0
@@ -1,7 +1,8 @@
1
1
  ---
2
- description: Markdown formatting for README, docs, and other .md files
3
- globs: "**/*.md"
4
- alwaysApply: false
2
+ name: markdown
3
+ description: Markdown formatting standards for plotly-print. Use when creating or editing Markdown files.
4
+ paths:
5
+ - "**/*.md"
5
6
  ---
6
7
 
7
8
  # Markdown
@@ -13,7 +14,7 @@ Use fenced code blocks with a language tag when the snippet has a language:
13
14
  ```python
14
15
  from pathlib import Path
15
16
 
16
- Path("data") / "out.csv"
17
+ Path('data') / 'out.csv'
17
18
  ```
18
19
 
19
20
  Do not leave unlabeled fences for Python, TOML, shell, or JSON. Plain fences are fine for output or prose examples with no language.
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: project-standards
3
+ description: Coding standards for plotly-print. Use before writing or reviewing code in this repository.
4
+ ---
5
+
6
+ # Project standards
7
+
8
+ Python package + QuickJS micro-DOM under `src/plotly_print/js/`. Source of truth: `pyproject.toml` (Python >= 3.12, uv). Package layout and entry points: `src/plotly_print/AGENTS.md`.
9
+
10
+ You are a lazy senior developer. Lazy means efficient, not careless. The best code is the code never written.
11
+
12
+ ## Before writing code
13
+
14
+ Read the task and the code it touches, trace the real flow end to end, then stop at the first rung that holds:
15
+
16
+ 1. Does this need to be built at all? (YAGNI)
17
+ 2. Does it already exist in this codebase? Reuse it.
18
+ 3. Does the standard library already do this? Use it.
19
+ 4. Does an already-declared dependency solve it? Use it.
20
+ 5. Can this be one boring line? Make it one line.
21
+ 6. Only then: write the minimum code that works.
22
+
23
+ Bug fix = root cause, not symptom. Grep every caller of the function you touch and fix the shared function once.
24
+
25
+ ## Toolchain
26
+
27
+ - Do not add a dependency unless it is declared in `pyproject.toml` (or the lockfile). Prefer stdlib.
28
+ - Ruff via `pyproject.toml`. After Python edits: `poe format`. After Markdown: `poe format_docs`.
29
+ - No JS formatter/linter; match `micro_dom.js`. Never hand-edit vendored Plotly bundles.
30
+
31
+ ## Comments and docs
32
+
33
+ - No docstrings except on base/abstract contracts and complex functions that need them.
34
+ - No unnecessary comments; if needed, explain why, not what.
35
+ - No section-divider comments in classes/functions (allowed in test classes). Group by proximity.
36
+
37
+ ## Language
38
+
39
+ Shared: ASCII only in identifiers/comments/docs (no emojis). No unnecessary imports.
40
+
41
+ Python: type-hint every function/method; f-strings; join with `/` on `Path` (avoid extra wrappers).
42
+
43
+ ## Quality
44
+
45
+ - Deletion over addition. Boring over clever. Fewest files; shortest working diff after understanding the problem.
46
+ - No unrequested abstractions, boilerplate, or dependencies. Question complex asks: does Y cover it?
47
+ - Prefer the edge-case-correct stdlib approach when sizes match.
48
+ - Deliberate ceilings: `ponytail:` comment naming the ceiling and upgrade path.
49
+ - Non-trivial logic: one smallest test that fails if it breaks. Run `poe test` before claiming done.
50
+ - No secrets, `.env`, or local virtualenvs in commits.
51
+
52
+ Not lazy about: understanding the problem, trust-boundary validation, error handling that prevents data loss, security, anything explicitly requested.
@@ -0,0 +1,36 @@
1
+ .DS_Store
2
+
3
+ .venv/
4
+
5
+ __pycache__/
6
+ *.py[cod]
7
+ .ruff_cache/
8
+ .pytest_cache/
9
+ .mypy_cache/
10
+
11
+ .env
12
+ .env.*
13
+
14
+ .idea/
15
+ .vscode/
16
+
17
+ build/
18
+ dist/
19
+ sdist/
20
+ wheels/
21
+ *.egg-info/
22
+
23
+ .artifacts/
24
+
25
+ # Platform-specific agent config, kept local by each maintainer.
26
+ .cursor/
27
+ .cursorignore
28
+ .cursorrules
29
+ .claude/
30
+ CLAUDE.md
31
+ CLAUDE.local.md
32
+ .codex/
33
+ AGENTS.override.md
34
+ .opencode/
35
+ opencode.json
36
+ opencode.jsonc
@@ -0,0 +1,24 @@
1
+ # Agent instructions
2
+
3
+ plotly-print: Python package + QuickJS micro-DOM for browser-less Plotly static export.
4
+
5
+ ## Context, loaded on demand
6
+
7
+ - Package map and flow: `src/plotly_print/AGENTS.md` (auto-loaded there).
8
+ - JS and micro-DOM rules: `src/plotly_print/js/AGENTS.md` (auto-loaded there).
9
+ - Tests: `tests/AGENTS.md` (auto-loaded there).
10
+ - Coding standards: skill `project-standards` (load before changing code).
11
+ - Markdown: skill `markdown` (load before editing `.md`).
12
+
13
+ ## Commands
14
+
15
+ `poe format` | `poe test` | `poe check` | `poe benchmark` | `poe format_docs`
16
+
17
+ After Python edits run `poe format`. After Markdown run `poe format_docs`.
18
+
19
+ ## Non-negotiables
20
+
21
+ - Vendored `src/plotly_print/js/plotly_comprehensive_2d.js`: never open whole-file, never edit. Use capped shell `grep -o ... | head`.
22
+ - No new dependency outside `pyproject.toml` and the lockfile.
23
+ - Scratch under `.artifacts/` (gitignored); do not commit.
24
+ - ASCII only in identifiers, comments, and docs; no emojis.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: plotly-print
3
- Version: 0.2.2
3
+ Version: 0.3.0
4
4
  Summary: Lightweight, browser-less static image exporter for Plotly
5
5
  Project-URL: Homepage, https://github.com/roman-kaczanowski/plotly-print
6
6
  Project-URL: Repository, https://github.com/roman-kaczanowski/plotly-print
@@ -75,6 +75,25 @@ After registration, existing calls such as `fig.write_image("chart.png")` use pl
75
75
 
76
76
  plotly-print targets 2D static charts. The bundled Plotly.js build and its licenses are documented in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
77
77
 
78
+ ## Fonts
79
+
80
+ Figures keep the font families you set, including `layout.font.family` and any per-trace or per-element override. If a family is not installed, plotly-print uses a system font. With no system fonts, it falls back to the bundled DejaVu Sans, DejaVu Serif, and DejaVu Sans Mono. Licenses for those fonts are in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
81
+
82
+ To use your own files, set the family on the figure and pass them with the export:
83
+
84
+ ```python
85
+ fig.update_layout(font={'family': 'Inter'})
86
+
87
+ plotly_print.write_image(
88
+ fig,
89
+ 'chart.png',
90
+ font_files=['fonts/Inter-Regular.ttf'],
91
+ # or: font_dirs=['fonts'],
92
+ )
93
+ ```
94
+
95
+ `font_files` and `font_dirs` also work with `to_svg`, `to_image`, and with `fig.write_image` after `plotly_print.register()`.
96
+
78
97
  <!-- BENCHMARK-START -->
79
98
 
80
99
  ## Benchmarks
@@ -49,6 +49,25 @@ After registration, existing calls such as `fig.write_image("chart.png")` use pl
49
49
 
50
50
  plotly-print targets 2D static charts. The bundled Plotly.js build and its licenses are documented in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
51
51
 
52
+ ## Fonts
53
+
54
+ Figures keep the font families you set, including `layout.font.family` and any per-trace or per-element override. If a family is not installed, plotly-print uses a system font. With no system fonts, it falls back to the bundled DejaVu Sans, DejaVu Serif, and DejaVu Sans Mono. Licenses for those fonts are in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
55
+
56
+ To use your own files, set the family on the figure and pass them with the export:
57
+
58
+ ```python
59
+ fig.update_layout(font={'family': 'Inter'})
60
+
61
+ plotly_print.write_image(
62
+ fig,
63
+ 'chart.png',
64
+ font_files=['fonts/Inter-Regular.ttf'],
65
+ # or: font_dirs=['fonts'],
66
+ )
67
+ ```
68
+
69
+ `font_files` and `font_dirs` also work with `to_svg`, `to_image`, and with `fig.write_image` after `plotly_print.register()`.
70
+
52
71
  <!-- BENCHMARK-START -->
53
72
 
54
73
  ## Benchmarks
@@ -0,0 +1,154 @@
1
+ # Third-party notices
2
+
3
+ ## plotly.js
4
+
5
+ File: `src/plotly_print/js/plotly_comprehensive_2d.js`
6
+
7
+ Redistributed plotly.js build (minified) used for offline / isolated 2D static
8
+ rendering in the embedded QuickJS runtime. The full `plotly.min.js` shipped with
9
+ the `plotly` Python package does not load in that runtime, so this smaller
10
+ bundle is included instead.
11
+
12
+ Copyright 2012-2026, Plotly, Inc.
13
+ All rights reserved.
14
+ Licensed under the MIT license.
15
+
16
+ ```text
17
+ The MIT License (MIT)
18
+
19
+ Copyright (c) 2014-2026 Plotly, Inc
20
+
21
+ Permission is hereby granted, free of charge, to any person obtaining a copy
22
+ of this software and associated documentation files (the "Software"), to deal
23
+ in the Software without restriction, including without limitation the rights
24
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25
+ copies of the Software, and to permit persons to whom the Software is
26
+ furnished to do so, subject to the following conditions:
27
+
28
+ The above copyright notice and this permission notice shall be included in
29
+ all copies or substantial portions of the Software.
30
+
31
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37
+ THE SOFTWARE.
38
+ ```
39
+
40
+ Upstream: https://github.com/plotly/plotly.js
41
+
42
+ ## DejaVu fonts
43
+
44
+ Files: `src/plotly_print/_fonts/DejaVuSans.ttf`,
45
+ `src/plotly_print/_fonts/DejaVuSans-Bold.ttf`,
46
+ `src/plotly_print/_fonts/DejaVuSerif.ttf`,
47
+ `src/plotly_print/_fonts/DejaVuSansMono.ttf`
48
+
49
+ Bundled as a fallback for systems without the fonts requested by a figure.
50
+ DejaVu changes are in the public domain; the original glyphs are covered by
51
+ the Bitstream Vera and Arev licenses below.
52
+
53
+ ```text
54
+ Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
55
+ Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
56
+
57
+
58
+ Bitstream Vera Fonts Copyright
59
+ ------------------------------
60
+
61
+ Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
62
+ a trademark of Bitstream, Inc.
63
+
64
+ Permission is hereby granted, free of charge, to any person obtaining a copy
65
+ of the fonts accompanying this license ("Fonts") and associated
66
+ documentation files (the "Font Software"), to reproduce and distribute the
67
+ Font Software, including without limitation the rights to use, copy, merge,
68
+ publish, distribute, and/or sell copies of the Font Software, and to permit
69
+ persons to whom the Font Software is furnished to do so, subject to the
70
+ following conditions:
71
+
72
+ The above copyright and trademark notices and this permission notice shall
73
+ be included in all copies of one or more of the Font Software typefaces.
74
+
75
+ The Font Software may be modified, altered, or added to, and in particular
76
+ the designs of glyphs or characters in the Fonts may be modified and
77
+ additional glyphs or characters may be added to the Fonts, only if the fonts
78
+ are renamed to names not containing either the words "Bitstream" or the word
79
+ "Vera".
80
+
81
+ This License becomes null and void to the extent applicable to Fonts or Font
82
+ Software that has been modified and is distributed under the "Bitstream
83
+ Vera" names.
84
+
85
+ The Font Software may be sold as part of a larger software package but no
86
+ copy of one or more of the Font Software typefaces may be sold by itself.
87
+
88
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
89
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
90
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
91
+ TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
92
+ FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
93
+ ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
94
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
95
+ THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
96
+ FONT SOFTWARE.
97
+
98
+ Except as contained in this notice, the names of Gnome, the Gnome
99
+ Foundation, and Bitstream Inc., shall not be used in advertising or
100
+ otherwise to promote the sale, use or other dealings in this Font Software
101
+ without prior written authorization from the Gnome Foundation or Bitstream
102
+ Inc., respectively. For further information, contact: fonts at gnome dot
103
+ org.
104
+
105
+ Arev Fonts Copyright
106
+ ------------------------------
107
+
108
+ Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
109
+
110
+ Permission is hereby granted, free of charge, to any person obtaining
111
+ a copy of the fonts accompanying this license ("Fonts") and
112
+ associated documentation files (the "Font Software"), to reproduce
113
+ and distribute the modifications to the Bitstream Vera Font Software,
114
+ including without limitation the rights to use, copy, merge, publish,
115
+ distribute, and/or sell copies of the Font Software, and to permit
116
+ persons to whom the Font Software is furnished to do so, subject to
117
+ the following conditions:
118
+
119
+ The above copyright and trademark notices and this permission notice
120
+ shall be included in all copies of one or more of the Font Software
121
+ typefaces.
122
+
123
+ The Font Software may be modified, altered, or added to, and in
124
+ particular the designs of glyphs or characters in the Fonts may be
125
+ modified and additional glyphs or characters may be added to the
126
+ Fonts, only if the fonts are renamed to names not containing either
127
+ the words "Tavmjong Bah" or the word "Arev".
128
+
129
+ This License becomes null and void to the extent applicable to Fonts
130
+ or Font Software that has been modified and is distributed under the
131
+ "Tavmjong Bah Arev" names.
132
+
133
+ The Font Software may be sold as part of a larger software package but
134
+ no copy of one or more of the Font Software typefaces may be sold by
135
+ itself.
136
+
137
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
138
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
139
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
140
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
141
+ TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
142
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
143
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
144
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
145
+ OTHER DEALINGS IN THE FONT SOFTWARE.
146
+
147
+ Except as contained in this notice, the name of Tavmjong Bah shall not
148
+ be used in advertising or otherwise to promote the sale, use or other
149
+ dealings in this Font Software without prior written authorization
150
+ from Tavmjong Bah. For further information, contact: tavmjong @ free
151
+ . fr.
152
+ ```
153
+
154
+ Upstream: https://github.com/dejavu-fonts/dejavu-fonts
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "plotly-print"
3
- version = "0.2.2"
3
+ version = "0.3.0"
4
4
  description = "Lightweight, browser-less static image exporter for Plotly"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -38,7 +38,11 @@ build-backend = "hatchling.build"
38
38
 
39
39
  [tool.hatch.build.targets.wheel]
40
40
  packages = ["src/plotly_print"]
41
- # benchmark/ is dev-only and intentionally omitted from the wheel.
41
+ # benchmark/ and nested agent instructions are dev-only.
42
+ exclude = [
43
+ "src/plotly_print/AGENTS.md",
44
+ "src/plotly_print/js/AGENTS.md",
45
+ ]
42
46
 
43
47
  [tool.uv]
44
48
  default-groups = ["dev", "test"]
@@ -52,6 +56,7 @@ test = [
52
56
  "kaleido>=0.2.1",
53
57
  "ruff",
54
58
  "mdformat",
59
+ "mdformat-frontmatter>=2.1.2",
55
60
  "mdformat-gfm",
56
61
  "mdformat-tables",
57
62
  ]
@@ -0,0 +1,30 @@
1
+ # Package map
2
+
3
+ Browser-less Plotly static export: QuickJS + micro-DOM + vendored Plotly 2D -> SVG -> resvg raster.
4
+
5
+ ## Flow
6
+
7
+ `core.to_svg` / `to_image` / `write_image` -> `engine.PrintEngine` (QuickJS) -> eval `micro_dom.js` + vendored Plotly -> SVG -> `raster.py` for png/jpeg/webp.
8
+
9
+ `plotly_hook.register` patches Plotly `to_image` / `write_image`.
10
+
11
+ ## Files
12
+
13
+ | Path | Job |
14
+ | ------------------------------- | ----------------------------------------------- |
15
+ | `core.py` | Public API; figure -> JSON |
16
+ | `engine.py` | QuickJS lifecycle; canvas -> PNG; typed arrays |
17
+ | `fonts.py` | Text metrics callable into JS; font fallbacks |
18
+ | `_fonts/` | Bundled DejaVu fallback fonts + license |
19
+ | `raster.py` | SVG -> raster (resvg) |
20
+ | `plotly_hook.py` | Monkeypatch Plotly |
21
+ | `js/micro_dom.js` | First-party DOM/SVG stubs (**edit here**) |
22
+ | `js/plotly_comprehensive_2d.js` | Vendored; **never** read or grep the whole file |
23
+
24
+ Start from this map. Open only listed files unless the task is outside `src/plotly_print/`.
25
+
26
+ ## Related context
27
+
28
+ - JS and micro-DOM: `js/AGENTS.md`.
29
+ - Tests: `../../tests/AGENTS.md`.
30
+ - Vendored bundle: opaque; never read or grep the whole file. Use capped shell `grep -o ... | head` for call shapes.
@@ -0,0 +1,98 @@
1
+ Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
2
+ Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
3
+
4
+
5
+ Bitstream Vera Fonts Copyright
6
+ ------------------------------
7
+
8
+ Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
9
+ a trademark of Bitstream, Inc.
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of the fonts accompanying this license ("Fonts") and associated
13
+ documentation files (the "Font Software"), to reproduce and distribute the
14
+ Font Software, including without limitation the rights to use, copy, merge,
15
+ publish, distribute, and/or sell copies of the Font Software, and to permit
16
+ persons to whom the Font Software is furnished to do so, subject to the
17
+ following conditions:
18
+
19
+ The above copyright and trademark notices and this permission notice shall
20
+ be included in all copies of one or more of the Font Software typefaces.
21
+
22
+ The Font Software may be modified, altered, or added to, and in particular
23
+ the designs of glyphs or characters in the Fonts may be modified and
24
+ additional glyphs or characters may be added to the Fonts, only if the fonts
25
+ are renamed to names not containing either the words "Bitstream" or the word
26
+ "Vera".
27
+
28
+ This License becomes null and void to the extent applicable to Fonts or Font
29
+ Software that has been modified and is distributed under the "Bitstream
30
+ Vera" names.
31
+
32
+ The Font Software may be sold as part of a larger software package but no
33
+ copy of one or more of the Font Software typefaces may be sold by itself.
34
+
35
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
36
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
37
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
38
+ TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
39
+ FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
40
+ ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
41
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
42
+ THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
43
+ FONT SOFTWARE.
44
+
45
+ Except as contained in this notice, the names of Gnome, the Gnome
46
+ Foundation, and Bitstream Inc., shall not be used in advertising or
47
+ otherwise to promote the sale, use or other dealings in this Font Software
48
+ without prior written authorization from the Gnome Foundation or Bitstream
49
+ Inc., respectively. For further information, contact: fonts at gnome dot
50
+ org.
51
+
52
+ Arev Fonts Copyright
53
+ ------------------------------
54
+
55
+ Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
56
+
57
+ Permission is hereby granted, free of charge, to any person obtaining
58
+ a copy of the fonts accompanying this license ("Fonts") and
59
+ associated documentation files (the "Font Software"), to reproduce
60
+ and distribute the modifications to the Bitstream Vera Font Software,
61
+ including without limitation the rights to use, copy, merge, publish,
62
+ distribute, and/or sell copies of the Font Software, and to permit
63
+ persons to whom the Font Software is furnished to do so, subject to
64
+ the following conditions:
65
+
66
+ The above copyright and trademark notices and this permission notice
67
+ shall be included in all copies of one or more of the Font Software
68
+ typefaces.
69
+
70
+ The Font Software may be modified, altered, or added to, and in
71
+ particular the designs of glyphs or characters in the Fonts may be
72
+ modified and additional glyphs or characters may be added to the
73
+ Fonts, only if the fonts are renamed to names not containing either
74
+ the words "Tavmjong Bah" or the word "Arev".
75
+
76
+ This License becomes null and void to the extent applicable to Fonts
77
+ or Font Software that has been modified and is distributed under the
78
+ "Tavmjong Bah Arev" names.
79
+
80
+ The Font Software may be sold as part of a larger software package but
81
+ no copy of one or more of the Font Software typefaces may be sold by
82
+ itself.
83
+
84
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
85
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
86
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
87
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
88
+ TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
89
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
90
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
91
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
92
+ OTHER DEALINGS IN THE FONT SOFTWARE.
93
+
94
+ Except as contained in this notice, the name of Tavmjong Bah shall not
95
+ be used in advertising or otherwise to promote the sale, use or other
96
+ dealings in this Font Software without prior written authorization
97
+ from Tavmjong Bah. For further information, contact: tavmjong @ free
98
+ . fr.
@@ -4,6 +4,7 @@ import os
4
4
  from typing import Any, BinaryIO
5
5
 
6
6
  from plotly_print.engine import get_engine
7
+ from plotly_print.fonts import FontPaths, resolve_font_dirs, resolve_font_files
7
8
  from plotly_print.raster import svg_to_jpeg, svg_to_png, svg_to_webp, write_raster
8
9
 
9
10
 
@@ -22,9 +23,11 @@ def to_svg(
22
23
  fig: Any,
23
24
  width: int | None = None,
24
25
  height: int | None = None,
26
+ font_files: FontPaths | None = None,
27
+ font_dirs: FontPaths | None = None,
25
28
  ) -> str:
26
29
  data, layout = _extract_figure_spec(fig)
27
- return get_engine().render_svg(data, layout, width=width, height=height)
30
+ return get_engine().render_svg(data, layout, width=width, height=height, font_files=font_files, font_dirs=font_dirs)
28
31
 
29
32
 
30
33
  def to_image(
@@ -33,18 +36,22 @@ def to_image(
33
36
  width: int | None = None,
34
37
  height: int | None = None,
35
38
  scale: float = 1.0,
39
+ font_files: FontPaths | None = None,
40
+ font_dirs: FontPaths | None = None,
36
41
  ) -> bytes:
37
42
  fmt = format.lower().strip()
38
- svg = to_svg(fig, width=width, height=height)
43
+ font_files = resolve_font_files(font_files) or None
44
+ font_dirs = resolve_font_dirs(font_dirs) or None
45
+ svg = to_svg(fig, width=width, height=height, font_files=font_files, font_dirs=font_dirs)
39
46
 
40
47
  if fmt == 'svg':
41
48
  return svg.encode('utf-8')
42
49
  if fmt == 'png':
43
- return svg_to_png(svg, width=width, height=height, scale=scale)
50
+ return svg_to_png(svg, width=width, height=height, scale=scale, font_files=font_files, font_dirs=font_dirs)
44
51
  if fmt in ('jpg', 'jpeg'):
45
- return svg_to_jpeg(svg, width=width, height=height, scale=scale)
52
+ return svg_to_jpeg(svg, width=width, height=height, scale=scale, font_files=font_files, font_dirs=font_dirs)
46
53
  if fmt == 'webp':
47
- return svg_to_webp(svg, width=width, height=height, scale=scale)
54
+ return svg_to_webp(svg, width=width, height=height, scale=scale, font_files=font_files, font_dirs=font_dirs)
48
55
  raise ValueError(f"Unsupported format: {format}. Supported: 'svg', 'png', 'jpeg', 'webp'")
49
56
 
50
57
 
@@ -55,6 +62,8 @@ def write_image(
55
62
  scale: float = 1.0,
56
63
  width: int | None = None,
57
64
  height: int | None = None,
65
+ font_files: FontPaths | None = None,
66
+ font_dirs: FontPaths | None = None,
58
67
  ) -> None:
59
68
  if format is None:
60
69
  if isinstance(file, (str, os.PathLike)):
@@ -64,7 +73,9 @@ def write_image(
64
73
  format = 'png'
65
74
 
66
75
  fmt = format.lower().strip()
67
- svg_str = to_svg(fig, width=width, height=height)
76
+ font_files = resolve_font_files(font_files) or None
77
+ font_dirs = resolve_font_dirs(font_dirs) or None
78
+ svg_str = to_svg(fig, width=width, height=height, font_files=font_files, font_dirs=font_dirs)
68
79
  if fmt == 'svg':
69
80
  if isinstance(file, (str, os.PathLike)):
70
81
  with open(file, 'w', encoding='utf-8') as f:
@@ -73,4 +84,13 @@ def write_image(
73
84
  file.write(svg_str.encode('utf-8'))
74
85
  return
75
86
 
76
- write_raster(svg_str, file, format=fmt, width=width, height=height, scale=scale)
87
+ write_raster(
88
+ svg_str,
89
+ file,
90
+ format=fmt,
91
+ width=width,
92
+ height=height,
93
+ scale=scale,
94
+ font_files=font_files,
95
+ font_dirs=font_dirs,
96
+ )