figpack 0.1.1__tar.gz → 0.1.3__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.

Potentially problematic release.


This version of figpack might be problematic. Click here for more details.

Files changed (55) hide show
  1. figpack-0.1.3/PKG-INFO +126 -0
  2. figpack-0.1.3/README.md +95 -0
  3. figpack-0.1.3/figpack/__init__.py +9 -0
  4. figpack-0.1.3/figpack/cli.py +312 -0
  5. {figpack-0.1.1 → figpack-0.1.3}/figpack/core/_bundle_utils.py +11 -1
  6. {figpack-0.1.1 → figpack-0.1.3}/figpack/core/_show_view.py +34 -8
  7. figpack-0.1.1/figpack/core/_upload_view.py → figpack-0.1.3/figpack/core/_upload_bundle.py +140 -49
  8. figpack-0.1.3/figpack/core/figpack_view.py +70 -0
  9. figpack-0.1.3/figpack/figpack-gui-dist/assets/index-BDa2iJW9.css +1 -0
  10. figpack-0.1.3/figpack/figpack-gui-dist/assets/index-ByLxmrzp.js +846 -0
  11. figpack-0.1.3/figpack/figpack-gui-dist/assets/neurosift-logo-CLsuwLMO.png +0 -0
  12. figpack-0.1.3/figpack/figpack-gui-dist/index.html +14 -0
  13. figpack-0.1.3/figpack/spike_sorting/__init__.py +5 -0
  14. figpack-0.1.3/figpack/spike_sorting/views/AutocorrelogramItem.py +41 -0
  15. figpack-0.1.3/figpack/spike_sorting/views/Autocorrelograms.py +76 -0
  16. figpack-0.1.3/figpack/spike_sorting/views/CrossCorrelogramItem.py +45 -0
  17. figpack-0.1.3/figpack/spike_sorting/views/CrossCorrelograms.py +82 -0
  18. figpack-0.1.3/figpack/spike_sorting/views/UnitSimilarityScore.py +40 -0
  19. figpack-0.1.3/figpack/spike_sorting/views/UnitsTable.py +68 -0
  20. figpack-0.1.3/figpack/spike_sorting/views/UnitsTableColumn.py +40 -0
  21. figpack-0.1.3/figpack/spike_sorting/views/UnitsTableRow.py +36 -0
  22. figpack-0.1.3/figpack/spike_sorting/views/__init__.py +23 -0
  23. figpack-0.1.3/figpack/views/Image.py +82 -0
  24. figpack-0.1.3/figpack/views/Markdown.py +34 -0
  25. figpack-0.1.3/figpack/views/MatplotlibFigure.py +65 -0
  26. figpack-0.1.3/figpack/views/PlotlyFigure.py +58 -0
  27. {figpack-0.1.1 → figpack-0.1.3}/figpack/views/__init__.py +4 -0
  28. figpack-0.1.3/figpack.egg-info/PKG-INFO +126 -0
  29. figpack-0.1.3/figpack.egg-info/SOURCES.txt +42 -0
  30. figpack-0.1.3/figpack.egg-info/entry_points.txt +2 -0
  31. figpack-0.1.3/figpack.egg-info/top_level.txt +1 -0
  32. {figpack-0.1.1 → figpack-0.1.3}/pyproject.toml +6 -2
  33. figpack-0.1.1/PKG-INFO +0 -33
  34. figpack-0.1.1/README.md +0 -2
  35. figpack-0.1.1/figpack/__init__.py +0 -7
  36. figpack-0.1.1/figpack/core/figpack_view.py +0 -62
  37. figpack-0.1.1/figpack/figpack-gui-dist/assets/index-BW-ONVCL.js +0 -65
  38. figpack-0.1.1/figpack/figpack-gui-dist/assets/index-CeWL3OeJ.css +0 -1
  39. figpack-0.1.1/figpack/figpack-gui-dist/index.html +0 -14
  40. figpack-0.1.1/figpack-gui/node_modules/flatted/python/flatted.py +0 -149
  41. figpack-0.1.1/figpack.egg-info/PKG-INFO +0 -33
  42. figpack-0.1.1/figpack.egg-info/SOURCES.txt +0 -26
  43. figpack-0.1.1/figpack.egg-info/top_level.txt +0 -3
  44. {figpack-0.1.1 → figpack-0.1.3}/LICENSE +0 -0
  45. {figpack-0.1.1 → figpack-0.1.3}/MANIFEST.in +0 -0
  46. {figpack-0.1.1 → figpack-0.1.3}/figpack/core/__init__.py +0 -0
  47. {figpack-0.1.1 → figpack-0.1.3}/figpack/views/Box.py +0 -0
  48. {figpack-0.1.1 → figpack-0.1.3}/figpack/views/LayoutItem.py +0 -0
  49. {figpack-0.1.1 → figpack-0.1.3}/figpack/views/Splitter.py +0 -0
  50. {figpack-0.1.1 → figpack-0.1.3}/figpack/views/TabLayout.py +0 -0
  51. {figpack-0.1.1 → figpack-0.1.3}/figpack/views/TabLayoutItem.py +0 -0
  52. {figpack-0.1.1 → figpack-0.1.3}/figpack/views/TimeseriesGraph.py +0 -0
  53. {figpack-0.1.1 → figpack-0.1.3}/figpack.egg-info/dependency_links.txt +0 -0
  54. {figpack-0.1.1 → figpack-0.1.3}/figpack.egg-info/requires.txt +0 -0
  55. {figpack-0.1.1 → figpack-0.1.3}/setup.cfg +0 -0
figpack-0.1.3/PKG-INFO ADDED
@@ -0,0 +1,126 @@
1
+ Metadata-Version: 2.4
2
+ Name: figpack
3
+ Version: 0.1.3
4
+ Summary: A Python package for creating shareable, interactive visualizations in the browser
5
+ Author-email: Jeremy Magland <jmagland@flatironinstitute.org>
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/magland/figpack
8
+ Project-URL: Repository, https://github.com/magland/figpack
9
+ Project-URL: Documentation, https://github.com/magland/figpack#readme
10
+ Project-URL: Bug Tracker, https://github.com/magland/figpack/issues
11
+ Keywords: visualization,plotting,timeseries,interactive
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: Apache Software License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.8
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Topic :: Scientific/Engineering :: Visualization
24
+ Requires-Python: >=3.8
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: numpy
28
+ Requires-Dist: zarr
29
+ Requires-Dist: requests
30
+ Dynamic: license-file
31
+
32
+ # figpack
33
+
34
+ A Python package for creating shareable, interactive visualizations in the browser.
35
+
36
+ ## Overview
37
+
38
+ figpack enables you to create interactive data visualizations that can be displayed in a web browser and optionally shared online. The package focuses on timeseries data visualization with support for complex, nested layouts.
39
+
40
+ ### Key Features
41
+
42
+ - **Interactive timeseries graphs** with line series, markers, and interval plots
43
+ - **Flexible layout system** with boxes, splitters, and tab layouts
44
+ - **Web-based rendering** that works in any modern browser
45
+ - **Shareable visualizations** that can be uploaded and shared via URLs
46
+ - **Zarr-based data storage** for efficient handling of large datasets
47
+
48
+ ## Installation
49
+
50
+ Install figpack using pip:
51
+
52
+ ```bash
53
+ pip install figpack
54
+ ```
55
+
56
+ ## Quick Start
57
+
58
+ ```python
59
+ import numpy as np
60
+ import figpack.views as vv
61
+
62
+ # Create a timeseries graph
63
+ graph = vv.TimeseriesGraph(y_label="Signal")
64
+
65
+ # Add some data
66
+ t = np.linspace(0, 10, 1000)
67
+ y = np.sin(2 * np.pi * t)
68
+ graph.add_line_series(name="sine wave", t=t, y=y, color="blue")
69
+
70
+ # Display the visualization
71
+ graph.show(open_in_browser=True)
72
+ ```
73
+
74
+ ## Examples
75
+
76
+ See the `examples/` directory.
77
+
78
+ ## Usage Modes
79
+
80
+ ### Local Development
81
+
82
+ ```python
83
+ view.show(open_in_browser=True)
84
+ ```
85
+
86
+ ### Sharing Online
87
+
88
+ Set the `FIGPACK_UPLOAD_PASSCODE` environment variable and use:
89
+
90
+ ```python
91
+ view.show(upload=True, open_in_browser=True)
92
+ ```
93
+
94
+ ### Development Mode
95
+
96
+ Set `_dev=True` in the call to show() to enable development mode, which allows for live updates and debugging with figpack-gui.
97
+
98
+ ## Command Line Interface
99
+
100
+ figpack includes a command-line interface for working with figures:
101
+
102
+ ### Download a Figure
103
+
104
+ ```bash
105
+ figpack download <figure-url> <dest.tar.gz>
106
+ ```
107
+
108
+ Download a figure from any figpack URL and save it as a local archive.
109
+
110
+ ### View a Figure Archive
111
+
112
+ ```bash
113
+ figpack view <figure.tar.gz>
114
+ ```
115
+
116
+ Extract and view a figure archive in your browser. The server will run locally until you press Enter.
117
+
118
+ Use `--port <number>` to specify a custom port.
119
+
120
+ ## License
121
+
122
+ Apache-2.0
123
+
124
+ ## Contributing
125
+
126
+ Visit the [GitHub repository](https://github.com/magland/figpack) for issues, contributions, and the latest updates.
@@ -0,0 +1,95 @@
1
+ # figpack
2
+
3
+ A Python package for creating shareable, interactive visualizations in the browser.
4
+
5
+ ## Overview
6
+
7
+ figpack enables you to create interactive data visualizations that can be displayed in a web browser and optionally shared online. The package focuses on timeseries data visualization with support for complex, nested layouts.
8
+
9
+ ### Key Features
10
+
11
+ - **Interactive timeseries graphs** with line series, markers, and interval plots
12
+ - **Flexible layout system** with boxes, splitters, and tab layouts
13
+ - **Web-based rendering** that works in any modern browser
14
+ - **Shareable visualizations** that can be uploaded and shared via URLs
15
+ - **Zarr-based data storage** for efficient handling of large datasets
16
+
17
+ ## Installation
18
+
19
+ Install figpack using pip:
20
+
21
+ ```bash
22
+ pip install figpack
23
+ ```
24
+
25
+ ## Quick Start
26
+
27
+ ```python
28
+ import numpy as np
29
+ import figpack.views as vv
30
+
31
+ # Create a timeseries graph
32
+ graph = vv.TimeseriesGraph(y_label="Signal")
33
+
34
+ # Add some data
35
+ t = np.linspace(0, 10, 1000)
36
+ y = np.sin(2 * np.pi * t)
37
+ graph.add_line_series(name="sine wave", t=t, y=y, color="blue")
38
+
39
+ # Display the visualization
40
+ graph.show(open_in_browser=True)
41
+ ```
42
+
43
+ ## Examples
44
+
45
+ See the `examples/` directory.
46
+
47
+ ## Usage Modes
48
+
49
+ ### Local Development
50
+
51
+ ```python
52
+ view.show(open_in_browser=True)
53
+ ```
54
+
55
+ ### Sharing Online
56
+
57
+ Set the `FIGPACK_UPLOAD_PASSCODE` environment variable and use:
58
+
59
+ ```python
60
+ view.show(upload=True, open_in_browser=True)
61
+ ```
62
+
63
+ ### Development Mode
64
+
65
+ Set `_dev=True` in the call to show() to enable development mode, which allows for live updates and debugging with figpack-gui.
66
+
67
+ ## Command Line Interface
68
+
69
+ figpack includes a command-line interface for working with figures:
70
+
71
+ ### Download a Figure
72
+
73
+ ```bash
74
+ figpack download <figure-url> <dest.tar.gz>
75
+ ```
76
+
77
+ Download a figure from any figpack URL and save it as a local archive.
78
+
79
+ ### View a Figure Archive
80
+
81
+ ```bash
82
+ figpack view <figure.tar.gz>
83
+ ```
84
+
85
+ Extract and view a figure archive in your browser. The server will run locally until you press Enter.
86
+
87
+ Use `--port <number>` to specify a custom port.
88
+
89
+ ## License
90
+
91
+ Apache-2.0
92
+
93
+ ## Contributing
94
+
95
+ Visit the [GitHub repository](https://github.com/magland/figpack) for issues, contributions, and the latest updates.
@@ -0,0 +1,9 @@
1
+ """
2
+ figpack - A Python package for creating shareable, interactive visualizations in the browser
3
+ """
4
+
5
+ __version__ = "0.1.0"
6
+ __author__ = "Jeremy Magland"
7
+ __email__ = "jmagland@flatironinstitute.org"
8
+
9
+ from . import spike_sorting
@@ -0,0 +1,312 @@
1
+ """
2
+ Command-line interface for figpack
3
+ """
4
+
5
+ import argparse
6
+ import sys
7
+ import pathlib
8
+ import tempfile
9
+ import tarfile
10
+ import json
11
+ import requests
12
+ import threading
13
+ import webbrowser
14
+ import socket
15
+ from concurrent.futures import ThreadPoolExecutor, as_completed
16
+ from urllib.parse import urlparse, urljoin
17
+ from typing import Dict, List, Tuple, Optional, Union
18
+ from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
19
+
20
+ from . import __version__
21
+ from .core._show_view import serve_files
22
+
23
+ MAX_WORKERS_FOR_DOWNLOAD = 16
24
+
25
+
26
+ def get_figure_base_url(figure_url: str) -> str:
27
+ """
28
+ Get the base URL from any figpack URL
29
+
30
+ Args:
31
+ figure_url: Any figpack URL (may or may not end with /index.html)
32
+
33
+ Returns:
34
+ str: The base URL for the figure directory
35
+ """
36
+ # Handle URLs that end with /index.html
37
+ if figure_url.endswith("/index.html"):
38
+ base_url = figure_url[:-11] # Remove "/index.html"
39
+ elif figure_url.endswith("/"):
40
+ base_url = figure_url[:-1] # Remove trailing slash
41
+ else:
42
+ # Assume it's already a directory URL
43
+ base_url = figure_url
44
+
45
+ # Ensure it ends with a slash for urljoin to work properly
46
+ if not base_url.endswith("/"):
47
+ base_url += "/"
48
+
49
+ return base_url
50
+
51
+
52
+ def download_file(
53
+ base_url: str, file_info: Dict, temp_dir: pathlib.Path
54
+ ) -> Tuple[str, bool]:
55
+ """
56
+ Download a single file from the figure
57
+
58
+ Args:
59
+ base_url: The base URL for the figure
60
+ file_info: Dictionary with 'path' and 'size' keys
61
+ temp_dir: Temporary directory to download to
62
+
63
+ Returns:
64
+ Tuple of (file_path, success)
65
+ """
66
+ file_path = file_info["path"]
67
+ file_url = urljoin(base_url, file_path)
68
+
69
+ try:
70
+ response = requests.get(file_url, timeout=30)
71
+ response.raise_for_status()
72
+
73
+ # Create directory structure if needed
74
+ local_file_path = temp_dir / file_path
75
+ local_file_path.parent.mkdir(parents=True, exist_ok=True)
76
+
77
+ # Write file content
78
+ if file_path.endswith(
79
+ (
80
+ ".json",
81
+ ".html",
82
+ ".css",
83
+ ".js",
84
+ ".zattrs",
85
+ ".zgroup",
86
+ ".zarray",
87
+ ".zmetadata",
88
+ )
89
+ ):
90
+ # Text files
91
+ local_file_path.write_text(response.text, encoding="utf-8")
92
+ else:
93
+ # Binary files
94
+ local_file_path.write_bytes(response.content)
95
+
96
+ return file_path, True
97
+
98
+ except Exception as e:
99
+ print(f"Failed to download {file_path}: {e}")
100
+ return file_path, False
101
+
102
+
103
+ def download_figure(figure_url: str, dest_path: str) -> None:
104
+ """
105
+ Download a figure from a figpack URL and save as tar.gz
106
+
107
+ Args:
108
+ figure_url: The figpack URL
109
+ dest_path: Destination path for the tar.gz file
110
+ """
111
+ print(f"Downloading figure from: {figure_url}")
112
+
113
+ # Get base URL
114
+ base_url = get_figure_base_url(figure_url)
115
+ print(f"Base URL: {base_url}")
116
+
117
+ # Check if manifest.json exists
118
+ manifest_url = urljoin(base_url, "manifest.json")
119
+ print("Checking for manifest.json...")
120
+
121
+ try:
122
+ response = requests.get(manifest_url, timeout=10)
123
+ response.raise_for_status()
124
+ manifest = response.json()
125
+ print(f"Found manifest with {len(manifest['files'])} files")
126
+ except requests.exceptions.RequestException as e:
127
+ print(f"Error: Could not retrieve manifest.json from {manifest_url}: {e}")
128
+ print("Make sure the URL points to a valid figpack figure with a manifest.")
129
+ sys.exit(1)
130
+ except json.JSONDecodeError as e:
131
+ print(f"Error: Invalid manifest.json format: {e}")
132
+ sys.exit(1)
133
+
134
+ # Create temporary directory for downloads
135
+ with tempfile.TemporaryDirectory() as temp_dir:
136
+ temp_path = pathlib.Path(temp_dir)
137
+
138
+ # Download all files in parallel
139
+ print(
140
+ f"Downloading {len(manifest['files'])} files with up to {MAX_WORKERS_FOR_DOWNLOAD} concurrent downloads..."
141
+ )
142
+
143
+ downloaded_count = 0
144
+ failed_files = []
145
+ count_lock = threading.Lock()
146
+
147
+ with ThreadPoolExecutor(max_workers=MAX_WORKERS_FOR_DOWNLOAD) as executor:
148
+ # Submit all download tasks
149
+ future_to_file = {
150
+ executor.submit(
151
+ download_file, base_url, file_info, temp_path
152
+ ): file_info["path"]
153
+ for file_info in manifest["files"]
154
+ }
155
+
156
+ # Process completed downloads
157
+ for future in as_completed(future_to_file):
158
+ file_path = future_to_file[future]
159
+ try:
160
+ downloaded_path, success = future.result()
161
+
162
+ with count_lock:
163
+ if success:
164
+ downloaded_count += 1
165
+ print(
166
+ f"Downloaded {downloaded_count}/{len(manifest['files'])}: {downloaded_path}"
167
+ )
168
+ else:
169
+ failed_files.append(downloaded_path)
170
+
171
+ except Exception as e:
172
+ with count_lock:
173
+ failed_files.append(file_path)
174
+ print(f"Failed to download {file_path}: {e}")
175
+
176
+ if failed_files:
177
+ print(f"Warning: Failed to download {len(failed_files)} files:")
178
+ for failed_file in failed_files:
179
+ print(f" - {failed_file}")
180
+
181
+ if len(failed_files) == len(manifest["files"]):
182
+ print("Error: Failed to download any files. Aborting.")
183
+ sys.exit(1)
184
+
185
+ # Save manifest.json to temp directory
186
+ manifest_path = temp_path / "manifest.json"
187
+ manifest_path.write_text(json.dumps(manifest, indent=2))
188
+ print("Added manifest.json to bundle")
189
+
190
+ # Create tar.gz file
191
+ print(f"Creating tar.gz archive: {dest_path}")
192
+ dest_pathlib = pathlib.Path(dest_path)
193
+ dest_pathlib.parent.mkdir(parents=True, exist_ok=True)
194
+
195
+ with tarfile.open(dest_path, "w:gz") as tar:
196
+ # Add all downloaded files (excluding figpack.json if it exists)
197
+ for file_path in temp_path.rglob("*"):
198
+ if file_path.is_file():
199
+ arcname = file_path.relative_to(temp_path)
200
+ # Skip figpack.json as requested
201
+ if str(arcname) != "figpack.json":
202
+ tar.add(file_path, arcname=arcname)
203
+
204
+ # Count files in archive (excluding directories)
205
+ archive_files = [
206
+ f for f in temp_path.rglob("*") if f.is_file() and f.name != "figpack.json"
207
+ ]
208
+ total_size = sum(f.stat().st_size for f in archive_files)
209
+
210
+ print(f"Archive created successfully!")
211
+ print(
212
+ f"Total files: {len(archive_files)} (including manifest.json, excluding figpack.json)"
213
+ )
214
+ print(f"Total size: {total_size / (1024 * 1024):.2f} MB")
215
+ print(f"Archive saved to: {dest_path}")
216
+
217
+
218
+ def view_figure(archive_path: str, port: Union[int, None] = None) -> None:
219
+ """
220
+ Extract and serve a figure archive locally
221
+
222
+ Args:
223
+ archive_path: Path to the tar.gz archive
224
+ port: Optional port number to serve on
225
+ """
226
+ archive_pathlib = pathlib.Path(archive_path)
227
+
228
+ if not archive_pathlib.exists():
229
+ print(f"Error: Archive file not found: {archive_path}")
230
+ sys.exit(1)
231
+
232
+ if not archive_pathlib.suffix.lower() in [".gz", ".tgz"] or not str(
233
+ archive_pathlib
234
+ ).endswith(".tar.gz"):
235
+ print(f"Error: Expected a .tar.gz file, got: {archive_path}")
236
+ sys.exit(1)
237
+
238
+ print(f"Extracting figure archive: {archive_path}")
239
+
240
+ # Create temporary directory and extract files
241
+ with tempfile.TemporaryDirectory(prefix="figpack_view_") as temp_dir:
242
+ temp_path = pathlib.Path(temp_dir)
243
+
244
+ try:
245
+ with tarfile.open(archive_path, "r:gz") as tar:
246
+ tar.extractall(temp_path)
247
+
248
+ # Count extracted files
249
+ extracted_files = list(temp_path.rglob("*"))
250
+ file_count = len([f for f in extracted_files if f.is_file()])
251
+ print(f"Extracted {file_count} files")
252
+
253
+ # Check if index.html exists
254
+ index_html = temp_path / "index.html"
255
+ if not index_html.exists():
256
+ print("Warning: No index.html found in archive")
257
+ print("Available files:")
258
+ for f in sorted(extracted_files):
259
+ if f.is_file():
260
+ print(f" {f.relative_to(temp_path)}")
261
+
262
+ # Serve the files
263
+ serve_files(
264
+ str(temp_path),
265
+ port=port,
266
+ open_in_browser=True,
267
+ allow_origin=None,
268
+ )
269
+
270
+ except tarfile.TarError as e:
271
+ print(f"Error: Failed to extract archive: {e}")
272
+ sys.exit(1)
273
+
274
+
275
+ def main():
276
+ """Main CLI entry point"""
277
+ parser = argparse.ArgumentParser(
278
+ description="figpack - A Python package for creating shareable, interactive visualizations",
279
+ prog="figpack",
280
+ )
281
+ parser.add_argument("--version", action="version", version=f"figpack {__version__}")
282
+
283
+ subparsers = parser.add_subparsers(dest="command", help="Available commands")
284
+
285
+ # Download command
286
+ download_parser = subparsers.add_parser(
287
+ "download", help="Download a figure from a figpack URL"
288
+ )
289
+ download_parser.add_argument("figure_url", help="The figpack URL to download")
290
+ download_parser.add_argument("dest", help="Destination path for the tar.gz file")
291
+
292
+ # View command
293
+ view_parser = subparsers.add_parser(
294
+ "view", help="Extract and serve a figure archive locally"
295
+ )
296
+ view_parser.add_argument("archive", help="Path to the tar.gz archive file")
297
+ view_parser.add_argument(
298
+ "--port", type=int, help="Port number to serve on (default: auto-select)"
299
+ )
300
+
301
+ args = parser.parse_args()
302
+
303
+ if args.command == "download":
304
+ download_figure(args.figure_url, args.dest)
305
+ elif args.command == "view":
306
+ view_figure(args.archive, port=args.port)
307
+ else:
308
+ parser.print_help()
309
+
310
+
311
+ if __name__ == "__main__":
312
+ main()
@@ -6,7 +6,9 @@ from .figpack_view import FigpackView
6
6
  thisdir = pathlib.Path(__file__).parent.resolve()
7
7
 
8
8
 
9
- def prepare_figure_bundle(view: FigpackView, tmpdir: str) -> None:
9
+ def prepare_figure_bundle(
10
+ view: FigpackView, tmpdir: str, *, title: str = None, description: str = None
11
+ ) -> None:
10
12
  """
11
13
  Prepare a figure bundle in the specified temporary directory.
12
14
 
@@ -18,6 +20,8 @@ def prepare_figure_bundle(view: FigpackView, tmpdir: str) -> None:
18
20
  Args:
19
21
  view: The figpack view to prepare
20
22
  tmpdir: The temporary directory to prepare the bundle in
23
+ title: Optional title for the figure
24
+ description: Optional description for the figure (markdown supported)
21
25
  """
22
26
  html_dir = thisdir / ".." / "figpack-gui-dist"
23
27
  if not os.path.exists(html_dir):
@@ -43,4 +47,10 @@ def prepare_figure_bundle(view: FigpackView, tmpdir: str) -> None:
43
47
  )
44
48
  view._write_to_zarr_group(zarr_group)
45
49
 
50
+ # Add title and description as attributes on the top-level zarr group
51
+ if title is not None:
52
+ zarr_group.attrs["title"] = title
53
+ if description is not None:
54
+ zarr_group.attrs["description"] = description
55
+
46
56
  zarr.consolidate_metadata(zarr_group.store)
@@ -12,6 +12,7 @@ from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
12
12
 
13
13
  from .figpack_view import FigpackView
14
14
  from ._bundle_utils import prepare_figure_bundle
15
+ from ._upload_bundle import _upload_bundle
15
16
 
16
17
  thisdir = pathlib.Path(__file__).parent.resolve()
17
18
 
@@ -22,16 +23,41 @@ def _show_view(
22
23
  open_in_browser: bool = False,
23
24
  port: Union[int, None] = None,
24
25
  allow_origin: Union[str, None] = None,
26
+ upload: bool = False,
27
+ title: Union[str, None] = None,
28
+ description: Union[str, None] = None,
25
29
  ):
26
30
  with tempfile.TemporaryDirectory(prefix="figpack_") as tmpdir:
27
- prepare_figure_bundle(view, tmpdir)
28
-
29
- serve_files(
30
- tmpdir,
31
- port=port,
32
- open_in_browser=open_in_browser,
33
- allow_origin=allow_origin,
34
- )
31
+ prepare_figure_bundle(view, tmpdir, title=title, description=description)
32
+
33
+ if upload:
34
+ # Check for required environment variable
35
+ passcode = os.environ.get("FIGPACK_UPLOAD_PASSCODE")
36
+ if not passcode:
37
+ raise EnvironmentError(
38
+ "FIGPACK_UPLOAD_PASSCODE environment variable must be set to upload views."
39
+ )
40
+
41
+ # Upload the bundle
42
+ print("Starting upload...")
43
+ figure_url = _upload_bundle(tmpdir, passcode)
44
+
45
+ if open_in_browser:
46
+ webbrowser.open(figure_url)
47
+ print(f"Opening {figure_url} in browser.")
48
+ # wait until user presses Enter
49
+ input("Press Enter to continue...")
50
+ else:
51
+ print(f"View the figure at: {figure_url}")
52
+
53
+ return figure_url
54
+ else:
55
+ serve_files(
56
+ tmpdir,
57
+ port=port,
58
+ open_in_browser=open_in_browser,
59
+ allow_origin=allow_origin,
60
+ )
35
61
 
36
62
 
37
63
  class CORSRequestHandler(SimpleHTTPRequestHandler):