figrecipe 0.5.0__py3-none-any.whl → 0.7.4__py3-none-any.whl

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 (189) hide show
  1. figrecipe/__init__.py +220 -819
  2. figrecipe/_api/__init__.py +48 -0
  3. figrecipe/_api/_extract.py +108 -0
  4. figrecipe/_api/_notebook.py +61 -0
  5. figrecipe/_api/_panel.py +46 -0
  6. figrecipe/_api/_save.py +191 -0
  7. figrecipe/_api/_seaborn_proxy.py +34 -0
  8. figrecipe/_api/_style_manager.py +153 -0
  9. figrecipe/_api/_subplots.py +333 -0
  10. figrecipe/_api/_validate.py +82 -0
  11. figrecipe/_dev/__init__.py +29 -0
  12. figrecipe/_dev/_plotters.py +76 -0
  13. figrecipe/_dev/_run_demos.py +56 -0
  14. figrecipe/_dev/demo_plotters/__init__.py +64 -0
  15. figrecipe/_dev/demo_plotters/_categories.py +81 -0
  16. figrecipe/_dev/demo_plotters/_figure_creators.py +119 -0
  17. figrecipe/_dev/demo_plotters/_helpers.py +31 -0
  18. figrecipe/_dev/demo_plotters/_registry.py +50 -0
  19. figrecipe/_dev/demo_plotters/bar_categorical/__init__.py +4 -0
  20. figrecipe/_dev/demo_plotters/bar_categorical/plot_bar.py +25 -0
  21. figrecipe/_dev/demo_plotters/bar_categorical/plot_barh.py +25 -0
  22. figrecipe/_dev/demo_plotters/contour_surface/__init__.py +4 -0
  23. figrecipe/_dev/demo_plotters/contour_surface/plot_contour.py +30 -0
  24. figrecipe/_dev/demo_plotters/contour_surface/plot_contourf.py +29 -0
  25. figrecipe/_dev/demo_plotters/contour_surface/plot_tricontour.py +28 -0
  26. figrecipe/_dev/demo_plotters/contour_surface/plot_tricontourf.py +28 -0
  27. figrecipe/_dev/demo_plotters/contour_surface/plot_tripcolor.py +29 -0
  28. figrecipe/_dev/demo_plotters/contour_surface/plot_triplot.py +25 -0
  29. figrecipe/_dev/demo_plotters/distribution/__init__.py +4 -0
  30. figrecipe/_dev/demo_plotters/distribution/plot_boxplot.py +24 -0
  31. figrecipe/_dev/demo_plotters/distribution/plot_ecdf.py +24 -0
  32. figrecipe/_dev/demo_plotters/distribution/plot_hist.py +24 -0
  33. figrecipe/_dev/demo_plotters/distribution/plot_hist2d.py +25 -0
  34. figrecipe/_dev/demo_plotters/distribution/plot_violinplot.py +25 -0
  35. figrecipe/_dev/demo_plotters/image_matrix/__init__.py +4 -0
  36. figrecipe/_dev/demo_plotters/image_matrix/plot_hexbin.py +25 -0
  37. figrecipe/_dev/demo_plotters/image_matrix/plot_imshow.py +23 -0
  38. figrecipe/_dev/demo_plotters/image_matrix/plot_matshow.py +23 -0
  39. figrecipe/_dev/demo_plotters/image_matrix/plot_pcolor.py +29 -0
  40. figrecipe/_dev/demo_plotters/image_matrix/plot_pcolormesh.py +29 -0
  41. figrecipe/_dev/demo_plotters/image_matrix/plot_spy.py +29 -0
  42. figrecipe/_dev/demo_plotters/line_curve/__init__.py +4 -0
  43. figrecipe/_dev/demo_plotters/line_curve/plot_errorbar.py +28 -0
  44. figrecipe/_dev/demo_plotters/line_curve/plot_fill.py +29 -0
  45. figrecipe/_dev/demo_plotters/line_curve/plot_fill_between.py +30 -0
  46. figrecipe/_dev/demo_plotters/line_curve/plot_fill_betweenx.py +28 -0
  47. figrecipe/_dev/demo_plotters/line_curve/plot_plot.py +28 -0
  48. figrecipe/_dev/demo_plotters/line_curve/plot_stackplot.py +29 -0
  49. figrecipe/_dev/demo_plotters/line_curve/plot_stairs.py +27 -0
  50. figrecipe/_dev/demo_plotters/line_curve/plot_step.py +27 -0
  51. figrecipe/_dev/demo_plotters/scatter_points/__init__.py +4 -0
  52. figrecipe/_dev/demo_plotters/scatter_points/plot_scatter.py +24 -0
  53. figrecipe/_dev/demo_plotters/special/__init__.py +4 -0
  54. figrecipe/_dev/demo_plotters/special/plot_eventplot.py +25 -0
  55. figrecipe/_dev/demo_plotters/special/plot_loglog.py +27 -0
  56. figrecipe/_dev/demo_plotters/special/plot_pie.py +27 -0
  57. figrecipe/_dev/demo_plotters/special/plot_semilogx.py +27 -0
  58. figrecipe/_dev/demo_plotters/special/plot_semilogy.py +27 -0
  59. figrecipe/_dev/demo_plotters/special/plot_stem.py +27 -0
  60. figrecipe/_dev/demo_plotters/spectral_signal/__init__.py +4 -0
  61. figrecipe/_dev/demo_plotters/spectral_signal/plot_acorr.py +24 -0
  62. figrecipe/_dev/demo_plotters/spectral_signal/plot_angle_spectrum.py +28 -0
  63. figrecipe/_dev/demo_plotters/spectral_signal/plot_cohere.py +29 -0
  64. figrecipe/_dev/demo_plotters/spectral_signal/plot_csd.py +29 -0
  65. figrecipe/_dev/demo_plotters/spectral_signal/plot_magnitude_spectrum.py +28 -0
  66. figrecipe/_dev/demo_plotters/spectral_signal/plot_phase_spectrum.py +28 -0
  67. figrecipe/_dev/demo_plotters/spectral_signal/plot_psd.py +29 -0
  68. figrecipe/_dev/demo_plotters/spectral_signal/plot_specgram.py +30 -0
  69. figrecipe/_dev/demo_plotters/spectral_signal/plot_xcorr.py +25 -0
  70. figrecipe/_dev/demo_plotters/vector_flow/__init__.py +4 -0
  71. figrecipe/_dev/demo_plotters/vector_flow/plot_barbs.py +30 -0
  72. figrecipe/_dev/demo_plotters/vector_flow/plot_quiver.py +30 -0
  73. figrecipe/_dev/demo_plotters/vector_flow/plot_streamplot.py +30 -0
  74. figrecipe/_editor/__init__.py +278 -0
  75. figrecipe/_editor/_bbox/__init__.py +43 -0
  76. figrecipe/_editor/_bbox/_collections.py +177 -0
  77. figrecipe/_editor/_bbox/_elements.py +159 -0
  78. figrecipe/_editor/_bbox/_extract.py +256 -0
  79. figrecipe/_editor/_bbox/_extract_axes.py +370 -0
  80. figrecipe/_editor/_bbox/_extract_text.py +342 -0
  81. figrecipe/_editor/_bbox/_lines.py +173 -0
  82. figrecipe/_editor/_bbox/_transforms.py +146 -0
  83. figrecipe/_editor/_flask_app.py +258 -0
  84. figrecipe/_editor/_helpers.py +242 -0
  85. figrecipe/_editor/_hitmap/__init__.py +76 -0
  86. figrecipe/_editor/_hitmap/_artists/__init__.py +21 -0
  87. figrecipe/_editor/_hitmap/_artists/_collections.py +345 -0
  88. figrecipe/_editor/_hitmap/_artists/_images.py +68 -0
  89. figrecipe/_editor/_hitmap/_artists/_lines.py +107 -0
  90. figrecipe/_editor/_hitmap/_artists/_patches.py +163 -0
  91. figrecipe/_editor/_hitmap/_artists/_text.py +190 -0
  92. figrecipe/_editor/_hitmap/_colors.py +181 -0
  93. figrecipe/_editor/_hitmap/_detect.py +137 -0
  94. figrecipe/_editor/_hitmap/_restore.py +154 -0
  95. figrecipe/_editor/_hitmap_main.py +182 -0
  96. figrecipe/_editor/_overrides.py +318 -0
  97. figrecipe/_editor/_preferences.py +135 -0
  98. figrecipe/_editor/_render_overrides.py +480 -0
  99. figrecipe/_editor/_renderer.py +199 -0
  100. figrecipe/_editor/_routes_axis.py +453 -0
  101. figrecipe/_editor/_routes_core.py +284 -0
  102. figrecipe/_editor/_routes_element.py +317 -0
  103. figrecipe/_editor/_routes_style.py +223 -0
  104. figrecipe/_editor/_templates/__init__.py +152 -0
  105. figrecipe/_editor/_templates/_html.py +502 -0
  106. figrecipe/_editor/_templates/_scripts/__init__.py +120 -0
  107. figrecipe/_editor/_templates/_scripts/_api.py +228 -0
  108. figrecipe/_editor/_templates/_scripts/_colors.py +485 -0
  109. figrecipe/_editor/_templates/_scripts/_core.py +436 -0
  110. figrecipe/_editor/_templates/_scripts/_debug_snapshot.py +186 -0
  111. figrecipe/_editor/_templates/_scripts/_element_editor.py +310 -0
  112. figrecipe/_editor/_templates/_scripts/_files.py +195 -0
  113. figrecipe/_editor/_templates/_scripts/_hitmap.py +509 -0
  114. figrecipe/_editor/_templates/_scripts/_inspector.py +315 -0
  115. figrecipe/_editor/_templates/_scripts/_labels.py +464 -0
  116. figrecipe/_editor/_templates/_scripts/_legend_drag.py +265 -0
  117. figrecipe/_editor/_templates/_scripts/_modals.py +226 -0
  118. figrecipe/_editor/_templates/_scripts/_overlays.py +292 -0
  119. figrecipe/_editor/_templates/_scripts/_panel_drag.py +334 -0
  120. figrecipe/_editor/_templates/_scripts/_panel_position.py +279 -0
  121. figrecipe/_editor/_templates/_scripts/_selection.py +237 -0
  122. figrecipe/_editor/_templates/_scripts/_tabs.py +89 -0
  123. figrecipe/_editor/_templates/_scripts/_view_mode.py +107 -0
  124. figrecipe/_editor/_templates/_scripts/_zoom.py +179 -0
  125. figrecipe/_editor/_templates/_styles/__init__.py +69 -0
  126. figrecipe/_editor/_templates/_styles/_base.py +64 -0
  127. figrecipe/_editor/_templates/_styles/_buttons.py +206 -0
  128. figrecipe/_editor/_templates/_styles/_color_input.py +123 -0
  129. figrecipe/_editor/_templates/_styles/_controls.py +265 -0
  130. figrecipe/_editor/_templates/_styles/_dynamic_props.py +144 -0
  131. figrecipe/_editor/_templates/_styles/_forms.py +126 -0
  132. figrecipe/_editor/_templates/_styles/_hitmap.py +184 -0
  133. figrecipe/_editor/_templates/_styles/_inspector.py +90 -0
  134. figrecipe/_editor/_templates/_styles/_labels.py +118 -0
  135. figrecipe/_editor/_templates/_styles/_modals.py +98 -0
  136. figrecipe/_editor/_templates/_styles/_overlays.py +130 -0
  137. figrecipe/_editor/_templates/_styles/_preview.py +225 -0
  138. figrecipe/_editor/_templates/_styles/_selection.py +73 -0
  139. figrecipe/_params/_DECORATION_METHODS.py +33 -0
  140. figrecipe/_params/_PLOTTING_METHODS.py +58 -0
  141. figrecipe/_params/__init__.py +9 -0
  142. figrecipe/_recorder.py +92 -110
  143. figrecipe/_recorder_utils.py +124 -0
  144. figrecipe/_reproducer/__init__.py +18 -0
  145. figrecipe/_reproducer/_core.py +498 -0
  146. figrecipe/_reproducer/_custom_plots.py +279 -0
  147. figrecipe/_reproducer/_seaborn.py +100 -0
  148. figrecipe/_reproducer/_violin.py +186 -0
  149. figrecipe/_seaborn.py +14 -9
  150. figrecipe/_serializer.py +2 -2
  151. figrecipe/_signatures/README.md +68 -0
  152. figrecipe/_signatures/__init__.py +12 -2
  153. figrecipe/_signatures/_kwargs.py +273 -0
  154. figrecipe/_signatures/_loader.py +114 -57
  155. figrecipe/_signatures/_parsing.py +147 -0
  156. figrecipe/_utils/__init__.py +6 -4
  157. figrecipe/_utils/_crop.py +10 -4
  158. figrecipe/_utils/_image_diff.py +37 -33
  159. figrecipe/_utils/_numpy_io.py +0 -1
  160. figrecipe/_utils/_units.py +11 -3
  161. figrecipe/_validator.py +12 -3
  162. figrecipe/_wrappers/_axes.py +193 -170
  163. figrecipe/_wrappers/_axes_helpers.py +136 -0
  164. figrecipe/_wrappers/_axes_plots.py +418 -0
  165. figrecipe/_wrappers/_axes_seaborn.py +157 -0
  166. figrecipe/_wrappers/_figure.py +277 -18
  167. figrecipe/_wrappers/_panel_labels.py +127 -0
  168. figrecipe/_wrappers/_plot_helpers.py +143 -0
  169. figrecipe/_wrappers/_violin_helpers.py +180 -0
  170. figrecipe/plt.py +0 -1
  171. figrecipe/pyplot.py +2 -1
  172. figrecipe/styles/__init__.py +12 -11
  173. figrecipe/styles/_dotdict.py +72 -0
  174. figrecipe/styles/_finalize.py +134 -0
  175. figrecipe/styles/_fonts.py +77 -0
  176. figrecipe/styles/_kwargs_converter.py +178 -0
  177. figrecipe/styles/_plot_styles.py +209 -0
  178. figrecipe/styles/_style_applier.py +60 -202
  179. figrecipe/styles/_style_loader.py +73 -121
  180. figrecipe/styles/_themes.py +151 -0
  181. figrecipe/styles/presets/MATPLOTLIB.yaml +95 -0
  182. figrecipe/styles/presets/SCITEX.yaml +181 -0
  183. figrecipe-0.7.4.dist-info/METADATA +429 -0
  184. figrecipe-0.7.4.dist-info/RECORD +188 -0
  185. figrecipe/_reproducer.py +0 -358
  186. figrecipe-0.5.0.dist-info/METADATA +0 -336
  187. figrecipe-0.5.0.dist-info/RECORD +0 -26
  188. {figrecipe-0.5.0.dist-info → figrecipe-0.7.4.dist-info}/WHEEL +0 -0
  189. {figrecipe-0.5.0.dist-info → figrecipe-0.7.4.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,502 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ HTML template for figure editor.
5
+ """
6
+
7
+ HTML_TEMPLATE = """
8
+ <!DOCTYPE html>
9
+ <html lang="en" data-theme="DARK_MODE_THEME_PLACEHOLDER">
10
+ <head>
11
+ <meta charset="UTF-8">
12
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
13
+ <title>figrecipe Editor</title>
14
+ <script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
15
+ <style>
16
+ /* STYLES_PLACEHOLDER */
17
+ </style>
18
+ </head>
19
+ <body>
20
+ <div class="editor-container">
21
+ <!-- Preview Panel -->
22
+ <div class="preview-panel">
23
+ <div class="preview-header">
24
+ <a href="https://scitex.ai" target="_blank" class="scitex-branding" title="FigRecipe - Part of SciTeX">
25
+ <img src="data:image/png;base64,SCITEX_ICON_PLACEHOLDER" alt="SciTeX" class="scitex-icon">
26
+ <span class="figrecipe-title">FigRecipe Editor</span>
27
+ </a>
28
+ <span id="server-start-time" style="font-size: 10px; color: #888; margin-left: 8px;">Started: SERVER_START_TIME_PLACEHOLDER</span>
29
+ <div class="file-switcher">
30
+ <select id="file-selector" class="file-selector" title="Switch between recipe files">
31
+ <option value="">Loading files...</option>
32
+ </select>
33
+ <button id="btn-new-figure" class="btn-new" title="Create new blank figure">+</button>
34
+ </div>
35
+ <div class="preview-controls">
36
+ <div class="download-dropdown">
37
+ <button id="btn-download-main" class="btn-primary download-main" title="Download as PNG">Download PNG</button>
38
+ <button id="btn-download-toggle" class="btn-primary download-toggle" title="More formats">▼</button>
39
+ <div id="download-menu" class="download-menu">
40
+ <button id="btn-download-png-menu" class="download-option active" data-format="png">PNG</button>
41
+ <button id="btn-download-svg-menu" class="download-option" data-format="svg">SVG</button>
42
+ <button id="btn-download-pdf-menu" class="download-option" data-format="pdf">PDF</button>
43
+ <hr style="margin: 4px 0; border: none; border-top: 1px solid #ddd;">
44
+ <button id="btn-download-csv-menu" class="download-option" data-format="csv" title="Export plot data as CSV">CSV (Data)</button>
45
+ </div>
46
+ </div>
47
+ <button id="btn-refresh" title="Refresh preview">Refresh</button>
48
+ <div class="zoom-controls">
49
+ <button id="btn-zoom-out" title="Zoom out (-)">−</button>
50
+ <span id="zoom-level">100%</span>
51
+ <button id="btn-zoom-in" title="Zoom in (+)">+</button>
52
+ <button id="btn-zoom-reset" title="Reset zoom (0)">⟲</button>
53
+ <button id="btn-zoom-fit" title="Fit to view (F)">Fit</button>
54
+ </div>
55
+ <button id="btn-ruler-grid" class="btn-ruler" title="Toggle rulers and grid overlay (G)">Ruler & Grid</button>
56
+ <button id="btn-shortcuts" class="btn-shortcuts" title="Show keyboard shortcuts (?)">⌨</button>
57
+ <label class="theme-toggle">
58
+ <input type="checkbox" id="dark-mode-toggle" DARK_MODE_CHECKED_PLACEHOLDER>
59
+ <span>Dark Mode</span>
60
+ </label>
61
+ </div>
62
+ </div>
63
+ <div class="preview-wrapper" id="preview-wrapper">
64
+ <div class="zoom-container" id="zoom-container">
65
+ <img id="preview-image" src="data:image/png;base64,IMAGE_BASE64_PLACEHOLDER" alt="Figure preview">
66
+ <svg id="hitregion-overlay" class="hitregion-overlay"></svg>
67
+ <svg id="selection-overlay" class="selection-overlay"></svg>
68
+ <svg id="ruler-overlay" class="ruler-overlay"></svg>
69
+ <svg id="grid-overlay" class="grid-overlay"></svg>
70
+ <svg id="column-overlay" class="column-overlay"></svg>
71
+ <canvas id="hitmap-canvas" style="display: none;"></canvas>
72
+ </div>
73
+ </div>
74
+ </div>
75
+
76
+ <!-- Controls Panel -->
77
+ <div class="controls-panel">
78
+ <div class="controls-header">
79
+ <h2>Properties</h2>
80
+ <div class="controls-actions">
81
+ <button id="btn-restore" class="btn-warning" title="Restore to original programmatic style">Restore</button>
82
+ <button id="btn-reset" class="btn-secondary" title="Reset to last saved">Reset</button>
83
+ <button id="btn-save" class="btn-primary">Save</button>
84
+ </div>
85
+ </div>
86
+ <div class="style-info">
87
+ <span class="style-label">Theme:</span>
88
+ <select id="theme-selector" class="theme-selector" title="Switch theme preset">
89
+ <option value="SCITEX">SCITEX</option>
90
+ <option value="MATPLOTLIB">MATPLOTLIB</option>
91
+ </select>
92
+ <div class="theme-actions">
93
+ <button id="btn-view-theme" class="btn-small" title="View theme contents">View</button>
94
+ <button id="btn-download-theme" class="btn-small" title="Download theme as YAML">Download</button>
95
+ <button id="btn-copy-theme" class="btn-small" title="Copy theme to clipboard">Copy</button>
96
+ </div>
97
+ </div>
98
+ <!-- Theme Modal -->
99
+ <div id="theme-modal" class="modal" style="display: none;">
100
+ <div class="modal-content">
101
+ <div class="modal-header">
102
+ <h3>Theme: <span id="theme-modal-name">SCITEX</span></h3>
103
+ <button id="theme-modal-close" class="modal-close">&times;</button>
104
+ </div>
105
+ <pre id="theme-content" class="theme-content-pre"></pre>
106
+ <div class="modal-footer">
107
+ <button id="theme-modal-download" class="btn-primary">Download YAML</button>
108
+ <button id="theme-modal-copy" class="btn-secondary">Copy to Clipboard</button>
109
+ </div>
110
+ </div>
111
+ </div>
112
+ <!-- Shortcuts Modal -->
113
+ <div id="shortcuts-modal" class="modal" style="display: none;">
114
+ <div class="modal-content shortcuts-modal-content">
115
+ <div class="modal-header">
116
+ <h3>Keyboard Shortcuts</h3>
117
+ <button id="shortcuts-modal-close" class="modal-close">&times;</button>
118
+ </div>
119
+ <div class="shortcuts-content">
120
+ <div class="shortcut-section">
121
+ <h4>General</h4>
122
+ <div class="shortcut-row"><span class="shortcut-keys"><kbd>Ctrl</kbd>+<kbd>S</kbd></span><span class="shortcut-desc">Save overrides</span></div>
123
+ <div class="shortcut-row"><span class="shortcut-keys"><kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>S</kbd></span><span class="shortcut-desc">Download PNG</span></div>
124
+ <div class="shortcut-row"><span class="shortcut-keys"><kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>I</kbd></span><span class="shortcut-desc">Debug snapshot</span></div>
125
+ <div class="shortcut-row"><span class="shortcut-keys"><kbd>F5</kbd> / <kbd>Ctrl</kbd>+<kbd>R</kbd></span><span class="shortcut-desc">Refresh preview</span></div>
126
+ <div class="shortcut-row"><span class="shortcut-keys"><kbd>Esc</kbd></span><span class="shortcut-desc">Clear selection</span></div>
127
+ <div class="shortcut-row"><span class="shortcut-keys"><kbd>R</kbd></span><span class="shortcut-desc">Reset to theme defaults</span></div>
128
+ </div>
129
+ <div class="shortcut-section">
130
+ <h4>Navigation</h4>
131
+ <div class="shortcut-row"><span class="shortcut-keys"><kbd>1</kbd></span><span class="shortcut-desc">Figure tab</span></div>
132
+ <div class="shortcut-row"><span class="shortcut-keys"><kbd>2</kbd></span><span class="shortcut-desc">Axis tab</span></div>
133
+ <div class="shortcut-row"><span class="shortcut-keys"><kbd>3</kbd></span><span class="shortcut-desc">Element tab</span></div>
134
+ </div>
135
+ <div class="shortcut-section">
136
+ <h4>View</h4>
137
+ <div class="shortcut-row"><span class="shortcut-keys"><kbd>G</kbd></span><span class="shortcut-desc">Toggle ruler &amp; grid</span></div>
138
+ <div class="shortcut-row"><span class="shortcut-keys"><kbd>+</kbd> / <kbd>-</kbd></span><span class="shortcut-desc">Zoom in/out</span></div>
139
+ <div class="shortcut-row"><span class="shortcut-keys"><kbd>0</kbd></span><span class="shortcut-desc">Reset zoom</span></div>
140
+ <div class="shortcut-row"><span class="shortcut-keys"><kbd>F</kbd></span><span class="shortcut-desc">Fit to view</span></div>
141
+ <div class="shortcut-row"><span class="shortcut-keys"><kbd>?</kbd></span><span class="shortcut-desc">Show this help</span></div>
142
+ </div>
143
+ <div class="shortcut-section">
144
+ <h4>Developer</h4>
145
+ <div class="shortcut-row"><span class="shortcut-keys"><kbd>Alt</kbd>+<kbd>I</kbd></span><span class="shortcut-desc">Toggle element inspector</span></div>
146
+ <div class="shortcut-row"><span class="shortcut-keys"><kbd>Alt</kbd>+<kbd>Shift</kbd>+<kbd>I</kbd></span><span class="shortcut-desc">Screenshot + console logs</span></div>
147
+ </div>
148
+ </div>
149
+ </div>
150
+ </div>
151
+ <div id="override-status" class="override-status" style="display: none;">
152
+ <span class="override-indicator">Manual overrides active</span>
153
+ <span id="override-timestamp" class="override-timestamp"></span>
154
+ </div>
155
+
156
+ <div class="controls-sections">
157
+ <!-- Tab Navigation -->
158
+ <div class="tab-navigation">
159
+ <button id="tab-figure" class="tab-btn active" title="Figure-level properties">Figure</button>
160
+ <button id="tab-axis" class="tab-btn" title="Axis-level properties">Axis</button>
161
+ <button id="tab-element" class="tab-btn" title="Element-specific properties">Element</button>
162
+ </div>
163
+
164
+ <!-- FIGURE TAB -->
165
+ <div id="tab-content-figure" class="tab-content active">
166
+ <!-- Dimensions Section -->
167
+ <details class="section" open>
168
+ <summary>Dimensions</summary>
169
+ <div class="section-content">
170
+ <div class="subsection">
171
+ <h4>Margins</h4>
172
+ <div class="form-grid">
173
+ <div class="form-row">
174
+ <label>Left</label>
175
+ <input type="number" id="margins_left_mm" step="1" min="0" max="50" placeholder="12">
176
+ </div>
177
+ <div class="form-row">
178
+ <label>Right</label>
179
+ <input type="number" id="margins_right_mm" step="1" min="0" max="50" placeholder="3">
180
+ </div>
181
+ <div class="form-row">
182
+ <label>Bottom</label>
183
+ <input type="number" id="margins_bottom_mm" step="1" min="0" max="50" placeholder="10">
184
+ </div>
185
+ <div class="form-row">
186
+ <label>Top</label>
187
+ <input type="number" id="margins_top_mm" step="1" min="0" max="50" placeholder="6">
188
+ </div>
189
+ </div>
190
+ </div>
191
+ <div class="subsection">
192
+ <h4>Spacing</h4>
193
+ <div class="form-row">
194
+ <label>Horizontal (mm)</label>
195
+ <input type="number" id="spacing_horizontal_mm" step="1" min="0" max="30" placeholder="8">
196
+ </div>
197
+ <div class="form-row">
198
+ <label>Vertical (mm)</label>
199
+ <input type="number" id="spacing_vertical_mm" step="1" min="0" max="30" placeholder="8">
200
+ </div>
201
+ </div>
202
+ </div>
203
+ </details>
204
+
205
+ <!-- Output Section -->
206
+ <details class="section">
207
+ <summary>Output</summary>
208
+ <div class="section-content">
209
+ <div class="form-row">
210
+ <label>DPI</label>
211
+ <input type="number" id="output_dpi" step="50" min="72" max="600">
212
+ </div>
213
+ <div class="form-row">
214
+ <label>Transparent</label>
215
+ <input type="checkbox" id="output_transparent">
216
+ </div>
217
+ </div>
218
+ </details>
219
+ </div>
220
+
221
+ <!-- AXIS TAB -->
222
+ <div id="tab-content-axis" class="tab-content">
223
+ <div class="tab-hint" id="axis-tab-hint">Select an axis element (title, label, ticks, legend) to edit</div>
224
+
225
+ <!-- Panel Position Section -->
226
+ <details class="section" open>
227
+ <summary>Panel Position</summary>
228
+ <div class="section-content">
229
+ <div class="form-row">
230
+ <label>Panel</label>
231
+ <select id="panel_selector">
232
+ <option value="0">Panel 0</option>
233
+ </select>
234
+ </div>
235
+ <div class="position-grid">
236
+ <div class="form-row">
237
+ <label>Left (mm)</label>
238
+ <input type="number" id="panel_left" step="1" min="0" placeholder="20">
239
+ </div>
240
+ <div class="form-row">
241
+ <label>Top (mm)</label>
242
+ <input type="number" id="panel_top" step="1" min="0" placeholder="15">
243
+ </div>
244
+ <div class="form-row">
245
+ <label>Width (mm)</label>
246
+ <input type="number" id="panel_width" step="1" min="0" placeholder="120">
247
+ </div>
248
+ <div class="form-row">
249
+ <label>Height (mm)</label>
250
+ <input type="number" id="panel_height" step="1" min="0" placeholder="90">
251
+ </div>
252
+ </div>
253
+ <div class="form-row" style="margin-top: 8px;">
254
+ <button id="apply_panel_position" class="btn-small">Apply Position</button>
255
+ </div>
256
+ </div>
257
+ </details>
258
+
259
+ <!-- Axes Size Section -->
260
+ <details class="section">
261
+ <summary>Axes Size</summary>
262
+ <div class="section-content">
263
+ <div class="form-row">
264
+ <label>Width (mm)</label>
265
+ <input type="number" id="axes_width_mm" step="1" min="10" max="200" placeholder="80">
266
+ </div>
267
+ <div class="form-row">
268
+ <label>Height (mm)</label>
269
+ <input type="number" id="axes_height_mm" step="1" min="10" max="200" placeholder="55">
270
+ </div>
271
+ </div>
272
+ </details>
273
+
274
+ <!-- Labels Section -->
275
+ <details class="section" open>
276
+ <summary>Labels</summary>
277
+ <div class="section-content">
278
+ <div class="form-row">
279
+ <label>Title</label>
280
+ <input type="text" id="label_title" class="label-input" placeholder="(no title)">
281
+ </div>
282
+ <div class="form-row">
283
+ <label>X Label</label>
284
+ <input type="text" id="label_xlabel" class="label-input" placeholder="(no xlabel)">
285
+ </div>
286
+ <div class="form-row">
287
+ <label>Y Label</label>
288
+ <input type="text" id="label_ylabel" class="label-input" placeholder="(no ylabel)">
289
+ </div>
290
+ <div class="form-row">
291
+ <label>Suptitle</label>
292
+ <input type="text" id="label_suptitle" class="label-input" placeholder="(no suptitle)">
293
+ </div>
294
+ </div>
295
+ </details>
296
+
297
+ <!-- Axis Type Section -->
298
+ <details class="section">
299
+ <summary>Axis Type</summary>
300
+ <div class="section-content">
301
+ <div class="form-row">
302
+ <label>X Axis</label>
303
+ <div class="axis-type-toggle">
304
+ <button id="xaxis-numerical" class="axis-type-btn active" data-axis="x" data-type="numerical">Numerical</button>
305
+ <button id="xaxis-categorical" class="axis-type-btn" data-axis="x" data-type="categorical">Categorical</button>
306
+ </div>
307
+ </div>
308
+ <div class="form-row">
309
+ <label>Y Axis</label>
310
+ <div class="axis-type-toggle">
311
+ <button id="yaxis-numerical" class="axis-type-btn active" data-axis="y" data-type="numerical">Numerical</button>
312
+ <button id="yaxis-categorical" class="axis-type-btn" data-axis="y" data-type="categorical">Categorical</button>
313
+ </div>
314
+ </div>
315
+ <div class="form-row" id="xaxis-labels-row" style="display: none;">
316
+ <label>X Labels</label>
317
+ <input type="text" id="xaxis_labels" class="label-input" placeholder="label1, label2, ...">
318
+ </div>
319
+ <div class="form-row" id="yaxis-labels-row" style="display: none;">
320
+ <label>Y Labels</label>
321
+ <input type="text" id="yaxis_labels" class="label-input" placeholder="label1, label2, ...">
322
+ </div>
323
+ </div>
324
+ </details>
325
+
326
+ <!-- Fonts Section -->
327
+ <details class="section">
328
+ <summary>Fonts</summary>
329
+ <div class="section-content">
330
+ <div class="form-row">
331
+ <label>Family</label>
332
+ <select id="fonts_family">
333
+ <option value="Arial">Arial</option>
334
+ <option value="DejaVu Sans">DejaVu Sans</option>
335
+ <option value="Helvetica">Helvetica</option>
336
+ <option value="Times New Roman">Times New Roman</option>
337
+ <option value="sans-serif">sans-serif</option>
338
+ <option value="serif">serif</option>
339
+ </select>
340
+ </div>
341
+ <div class="form-row">
342
+ <label>Axis Label (pt)</label>
343
+ <input type="number" id="fonts_axis_label_pt" step="0.5" min="4" max="24">
344
+ </div>
345
+ <div class="form-row">
346
+ <label>Tick Label (pt)</label>
347
+ <input type="number" id="fonts_tick_label_pt" step="0.5" min="4" max="24">
348
+ </div>
349
+ <div class="form-row">
350
+ <label>Title (pt)</label>
351
+ <input type="number" id="fonts_title_pt" step="0.5" min="4" max="24">
352
+ </div>
353
+ <div class="form-row">
354
+ <label>Suptitle (pt)</label>
355
+ <input type="number" id="fonts_suptitle_pt" step="0.5" min="4" max="30">
356
+ </div>
357
+ <div class="form-row">
358
+ <label>Legend (pt)</label>
359
+ <input type="number" id="fonts_legend_pt" step="0.5" min="4" max="24">
360
+ </div>
361
+ </div>
362
+ </details>
363
+
364
+ <!-- Ticks Section -->
365
+ <details class="section">
366
+ <summary>Ticks</summary>
367
+ <div class="section-content">
368
+ <div class="form-row">
369
+ <label>Length (mm)</label>
370
+ <input type="number" id="ticks_length_mm" step="0.1" min="0.5" max="5">
371
+ </div>
372
+ <div class="form-row">
373
+ <label>Thickness (mm)</label>
374
+ <input type="number" id="ticks_thickness_mm" step="0.05" min="0.1" max="2">
375
+ </div>
376
+ <div class="form-row">
377
+ <label>Direction</label>
378
+ <select id="ticks_direction">
379
+ <option value="out">Out</option>
380
+ <option value="in">In</option>
381
+ <option value="inout">Both</option>
382
+ </select>
383
+ </div>
384
+ <div class="form-row">
385
+ <label>N Ticks</label>
386
+ <input type="number" id="ticks_n_ticks" step="1" min="2" max="20">
387
+ </div>
388
+ </div>
389
+ </details>
390
+
391
+ <!-- Spines Section -->
392
+ <details class="section">
393
+ <summary>Spines</summary>
394
+ <div class="section-content">
395
+ <div class="form-row">
396
+ <label>Thickness (mm)</label>
397
+ <input type="number" id="axes_thickness_mm" step="0.05" min="0.1" max="2" placeholder="0.35">
398
+ </div>
399
+ <div class="form-row">
400
+ <label>Hide Top</label>
401
+ <input type="checkbox" id="behavior_hide_top_spine">
402
+ </div>
403
+ <div class="form-row">
404
+ <label>Hide Right</label>
405
+ <input type="checkbox" id="behavior_hide_right_spine">
406
+ </div>
407
+ <div class="form-row">
408
+ <label>Grid</label>
409
+ <input type="checkbox" id="behavior_grid">
410
+ </div>
411
+ </div>
412
+ </details>
413
+
414
+ <!-- Legend Section -->
415
+ <details class="section">
416
+ <summary>Legend</summary>
417
+ <div class="section-content">
418
+ <div class="form-row">
419
+ <label>Visible</label>
420
+ <input type="checkbox" id="legend_visible" checked>
421
+ </div>
422
+ <div class="form-row">
423
+ <label>Show Frame</label>
424
+ <input type="checkbox" id="legend_frameon">
425
+ </div>
426
+ <div class="form-row">
427
+ <label>Location</label>
428
+ <select id="legend_loc">
429
+ <option value="best">Best</option>
430
+ <option value="upper right">Upper Right</option>
431
+ <option value="upper left">Upper Left</option>
432
+ <option value="lower right">Lower Right</option>
433
+ <option value="lower left">Lower Left</option>
434
+ <option value="center">Center</option>
435
+ <option value="center left">Center Left</option>
436
+ <option value="center right">Center Right</option>
437
+ <option value="lower center">Lower Center</option>
438
+ <option value="upper center">Upper Center</option>
439
+ <option value="custom">Custom (xy)</option>
440
+ </select>
441
+ </div>
442
+ <div id="legend-custom-pos" class="legend-custom-pos" style="display: none;">
443
+ <div class="form-row">
444
+ <label>X (0-1)</label>
445
+ <input type="number" id="legend_x" step="0.05" min="0" max="1.5" value="1.02" placeholder="1.02">
446
+ </div>
447
+ <div class="form-row">
448
+ <label>Y (0-1)</label>
449
+ <input type="number" id="legend_y" step="0.05" min="0" max="1.5" value="1" placeholder="1">
450
+ </div>
451
+ <div class="form-hint">Coordinates are relative to axes (0-1). Values >1 place legend outside.</div>
452
+ </div>
453
+ <div class="form-row">
454
+ <label>Alpha</label>
455
+ <input type="range" id="legend_alpha" min="0" max="1" step="0.1">
456
+ <span id="legend_alpha_value">0.8</span>
457
+ </div>
458
+ <div class="form-row">
459
+ <label>Background</label>
460
+ <input type="color" id="legend_bg" value="#ffffff">
461
+ </div>
462
+ </div>
463
+ </details>
464
+ </div>
465
+
466
+ <!-- ELEMENT TAB -->
467
+ <div id="tab-content-element" class="tab-content">
468
+ <div class="tab-hint" id="element-tab-hint">
469
+ <p>Select a plot element to edit its properties</p>
470
+ <p class="hint-sub">Click on lines, scatter, bars, etc. in the preview</p>
471
+ </div>
472
+
473
+ <!-- Selected element info -->
474
+ <div id="selected-element-panel" style="display: none;">
475
+ <div class="selected-element-header">
476
+ <span class="element-type-badge" id="element-type-badge">line</span>
477
+ <span class="element-name" id="element-name">element</span>
478
+ </div>
479
+ </div>
480
+
481
+ <!-- Dynamic call properties (populated when element selected) -->
482
+ <div id="dynamic-call-properties" class="dynamic-call-properties"></div>
483
+ </div>
484
+ </div>
485
+ </div>
486
+ </div>
487
+
488
+ <script>
489
+ // Initial data from server
490
+ const initialBboxes = BBOXES_PLACEHOLDER;
491
+ const initialColorMap = COLOR_MAP_PLACEHOLDER;
492
+ const initialValues = INITIAL_VALUES_PLACEHOLDER;
493
+ const imgWidth = IMG_WIDTH_PLACEHOLDER;
494
+ const imgHeight = IMG_HEIGHT_PLACEHOLDER;
495
+
496
+ /* SCRIPTS_PLACEHOLDER */
497
+ </script>
498
+ </body>
499
+ </html>
500
+ """
501
+
502
+ __all__ = ["HTML_TEMPLATE"]
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """JavaScript modules for the figure editor.
4
+
5
+ This package contains modular JavaScript organized by functionality:
6
+ - _api.py: API calls (save, load, update, download)
7
+ - _colors.py: Color presets and conversion utilities
8
+ - _core.py: State variables and initialization
9
+ - _debug_snapshot.py: Screenshot + console log capture (Ctrl+Alt+I)
10
+ - _element_editor.py: Dynamic form fields and call properties
11
+ - _files.py: File switching functionality
12
+ - _hitmap.py: Hitmap loading and hit region drawing
13
+ - _inspector.py: Element inspector debugging
14
+ - _labels.py: Label inputs and axis/legend controls
15
+ - _modals.py: Theme and shortcuts modals
16
+ - _panel_drag.py: Panel drag-to-move (click+drag on empty panel area)
17
+ - _legend_drag.py: Legend drag-to-move (click+drag on legend)
18
+ - _panel_position.py: Panel position editing (left, bottom, width, height)
19
+ - _overlays.py: Measurement overlays (ruler, grid, columns)
20
+ - _selection.py: Selection drawing and property sync
21
+ - _tabs.py: Tab navigation (Figure/Axis/Element)
22
+ - _view_mode.py: View mode management (all/selected)
23
+ - _zoom.py: Zoom/pan functionality
24
+ """
25
+
26
+ from ._api import SCRIPTS_API
27
+ from ._colors import SCRIPTS_COLORS
28
+ from ._core import SCRIPTS_CORE
29
+ from ._debug_snapshot import SCRIPTS_DEBUG_SNAPSHOT
30
+ from ._element_editor import SCRIPTS_ELEMENT_EDITOR
31
+ from ._files import SCRIPTS_FILES
32
+ from ._hitmap import SCRIPTS_HITMAP
33
+ from ._inspector import SCRIPTS_INSPECTOR
34
+ from ._labels import SCRIPTS_LABELS
35
+ from ._legend_drag import SCRIPTS_LEGEND_DRAG
36
+ from ._modals import SCRIPTS_MODALS
37
+ from ._overlays import SCRIPTS_OVERLAYS
38
+ from ._panel_drag import SCRIPTS_PANEL_DRAG
39
+ from ._panel_position import SCRIPTS_PANEL_POSITION
40
+ from ._selection import SCRIPTS_SELECTION
41
+ from ._tabs import SCRIPTS_TABS
42
+ from ._view_mode import SCRIPTS_VIEW_MODE
43
+ from ._zoom import SCRIPTS_ZOOM
44
+
45
+ # Combined SCRIPTS constant for backward compatibility
46
+ # Order matters: debug snapshot first (for console interception), then core/state, then features
47
+ SCRIPTS = (
48
+ SCRIPTS_DEBUG_SNAPSHOT
49
+ + SCRIPTS_CORE
50
+ + SCRIPTS_TABS
51
+ + SCRIPTS_VIEW_MODE
52
+ + SCRIPTS_COLORS
53
+ + SCRIPTS_HITMAP
54
+ + SCRIPTS_SELECTION
55
+ + SCRIPTS_ELEMENT_EDITOR
56
+ + SCRIPTS_LABELS
57
+ + SCRIPTS_API
58
+ + SCRIPTS_MODALS
59
+ + SCRIPTS_ZOOM
60
+ + SCRIPTS_OVERLAYS
61
+ + SCRIPTS_INSPECTOR
62
+ + SCRIPTS_FILES
63
+ + SCRIPTS_PANEL_POSITION
64
+ + SCRIPTS_PANEL_DRAG
65
+ + SCRIPTS_LEGEND_DRAG
66
+ )
67
+
68
+
69
+ def get_all_scripts():
70
+ """Return all scripts as a dictionary for testing.
71
+
72
+ Returns
73
+ -------
74
+ dict
75
+ Mapping of script name to script content.
76
+ """
77
+ return {
78
+ "api": SCRIPTS_API,
79
+ "colors": SCRIPTS_COLORS,
80
+ "core": SCRIPTS_CORE,
81
+ "debug_snapshot": SCRIPTS_DEBUG_SNAPSHOT,
82
+ "element_editor": SCRIPTS_ELEMENT_EDITOR,
83
+ "files": SCRIPTS_FILES,
84
+ "hitmap": SCRIPTS_HITMAP,
85
+ "inspector": SCRIPTS_INSPECTOR,
86
+ "labels": SCRIPTS_LABELS,
87
+ "legend_drag": SCRIPTS_LEGEND_DRAG,
88
+ "modals": SCRIPTS_MODALS,
89
+ "overlays": SCRIPTS_OVERLAYS,
90
+ "panel_drag": SCRIPTS_PANEL_DRAG,
91
+ "panel_position": SCRIPTS_PANEL_POSITION,
92
+ "selection": SCRIPTS_SELECTION,
93
+ "tabs": SCRIPTS_TABS,
94
+ "view_mode": SCRIPTS_VIEW_MODE,
95
+ "zoom": SCRIPTS_ZOOM,
96
+ }
97
+
98
+
99
+ __all__ = [
100
+ "SCRIPTS",
101
+ "SCRIPTS_API",
102
+ "SCRIPTS_COLORS",
103
+ "SCRIPTS_CORE",
104
+ "SCRIPTS_DEBUG_SNAPSHOT",
105
+ "SCRIPTS_ELEMENT_EDITOR",
106
+ "SCRIPTS_FILES",
107
+ "SCRIPTS_HITMAP",
108
+ "SCRIPTS_INSPECTOR",
109
+ "SCRIPTS_LABELS",
110
+ "SCRIPTS_LEGEND_DRAG",
111
+ "SCRIPTS_MODALS",
112
+ "SCRIPTS_OVERLAYS",
113
+ "SCRIPTS_PANEL_DRAG",
114
+ "SCRIPTS_PANEL_POSITION",
115
+ "SCRIPTS_SELECTION",
116
+ "SCRIPTS_TABS",
117
+ "SCRIPTS_VIEW_MODE",
118
+ "SCRIPTS_ZOOM",
119
+ "get_all_scripts",
120
+ ]