figpack 0.2.16__py3-none-any.whl → 0.2.17__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 (39) hide show
  1. figpack/__init__.py +2 -3
  2. figpack/core/__init__.py +2 -2
  3. figpack/core/_bundle_utils.py +56 -18
  4. figpack/core/extension_view.py +7 -25
  5. figpack/core/figpack_extension.py +0 -71
  6. figpack/figpack-figure-dist/assets/index-DBwmtEpB.js +91 -0
  7. figpack/figpack-figure-dist/assets/{index-D9a3K6eW.css → index-DHWczh-Q.css} +1 -1
  8. figpack/figpack-figure-dist/index.html +2 -2
  9. figpack/views/PlotlyExtension/PlotlyExtension.py +4 -50
  10. figpack/views/PlotlyExtension/_plotly_extension.py +46 -0
  11. figpack/views/PlotlyExtension/plotly_view.js +84 -80
  12. figpack/views/__init__.py +1 -0
  13. {figpack-0.2.16.dist-info → figpack-0.2.17.dist-info}/METADATA +1 -1
  14. figpack-0.2.17.dist-info/RECORD +43 -0
  15. figpack/figpack-figure-dist/assets/index-DtOnN02w.js +0 -846
  16. figpack/franklab/__init__.py +0 -5
  17. figpack/franklab/views/TrackAnimation.py +0 -154
  18. figpack/franklab/views/__init__.py +0 -9
  19. figpack/spike_sorting/__init__.py +0 -5
  20. figpack/spike_sorting/views/AutocorrelogramItem.py +0 -32
  21. figpack/spike_sorting/views/Autocorrelograms.py +0 -116
  22. figpack/spike_sorting/views/AverageWaveforms.py +0 -146
  23. figpack/spike_sorting/views/CrossCorrelogramItem.py +0 -35
  24. figpack/spike_sorting/views/CrossCorrelograms.py +0 -131
  25. figpack/spike_sorting/views/RasterPlot.py +0 -284
  26. figpack/spike_sorting/views/RasterPlotItem.py +0 -28
  27. figpack/spike_sorting/views/SpikeAmplitudes.py +0 -364
  28. figpack/spike_sorting/views/SpikeAmplitudesItem.py +0 -38
  29. figpack/spike_sorting/views/UnitMetricsGraph.py +0 -127
  30. figpack/spike_sorting/views/UnitSimilarityScore.py +0 -40
  31. figpack/spike_sorting/views/UnitsTable.py +0 -82
  32. figpack/spike_sorting/views/UnitsTableColumn.py +0 -40
  33. figpack/spike_sorting/views/UnitsTableRow.py +0 -36
  34. figpack/spike_sorting/views/__init__.py +0 -41
  35. figpack-0.2.16.dist-info/RECORD +0 -61
  36. {figpack-0.2.16.dist-info → figpack-0.2.17.dist-info}/WHEEL +0 -0
  37. {figpack-0.2.16.dist-info → figpack-0.2.17.dist-info}/entry_points.txt +0 -0
  38. {figpack-0.2.16.dist-info → figpack-0.2.17.dist-info}/licenses/LICENSE +0 -0
  39. {figpack-0.2.16.dist-info → figpack-0.2.17.dist-info}/top_level.txt +0 -0
figpack/__init__.py CHANGED
@@ -2,17 +2,16 @@
2
2
  figpack - A Python package for creating shareable, interactive visualizations in the browser
3
3
  """
4
4
 
5
- __version__ = "0.2.16"
5
+ __version__ = "0.2.17"
6
6
 
7
7
  from .cli import view_figure
8
- from .core import FigpackView, FigpackExtension, ExtensionRegistry, ExtensionView
8
+ from .core import FigpackView, FigpackExtension, ExtensionView
9
9
  from .core.zarr import Group
10
10
 
11
11
  __all__ = [
12
12
  "view_figure",
13
13
  "FigpackView",
14
14
  "FigpackExtension",
15
- "ExtensionRegistry",
16
15
  "ExtensionView",
17
16
  "Group",
18
17
  ]
figpack/core/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from .figpack_view import FigpackView
2
- from .figpack_extension import FigpackExtension, ExtensionRegistry
2
+ from .figpack_extension import FigpackExtension
3
3
  from .extension_view import ExtensionView
4
4
 
5
- __all__ = ["FigpackView", "FigpackExtension", "ExtensionRegistry", "ExtensionView"]
5
+ __all__ = ["FigpackView", "FigpackExtension", "ExtensionView"]
@@ -1,11 +1,12 @@
1
1
  import os
2
2
  import pathlib
3
+ import json
3
4
  from typing import Set
4
5
 
5
6
  import zarr
6
7
 
7
8
  from .figpack_view import FigpackView
8
- from .figpack_extension import ExtensionRegistry
9
+ from .figpack_extension import FigpackExtension
9
10
  from .extension_view import ExtensionView
10
11
  from .zarr import Group, _check_zarr_version
11
12
 
@@ -68,6 +69,9 @@ def prepare_figure_bundle(
68
69
  required_extensions = _discover_required_extensions(view)
69
70
  _write_extension_files(required_extensions, tmpdir)
70
71
 
72
+ # Generate extension manifest
73
+ _write_extension_manifest(required_extensions, tmpdir)
74
+
71
75
  zarr.consolidate_metadata(zarr_group._zarr_group.store)
72
76
  finally:
73
77
  if _check_zarr_version() == 3:
@@ -84,7 +88,8 @@ def _discover_required_extensions(view: FigpackView) -> Set[str]:
84
88
  Returns:
85
89
  Set of extension names required by this view hierarchy
86
90
  """
87
- extensions = set()
91
+ extension_names_discovered = set()
92
+ extensions_discovered = []
88
93
  visited = set() # Prevent infinite recursion
89
94
 
90
95
  def _collect_extensions(v: FigpackView):
@@ -95,7 +100,9 @@ def _discover_required_extensions(view: FigpackView) -> Set[str]:
95
100
 
96
101
  # Check if this view is an extension view
97
102
  if isinstance(v, ExtensionView):
98
- extensions.add(v.extension_name)
103
+ if v.extension.name not in extension_names_discovered:
104
+ extension_names_discovered.add(v.extension.name)
105
+ extensions_discovered.append(v.extension)
99
106
 
100
107
  # Recursively check all attributes that might contain child views
101
108
  for attr_name in dir(v):
@@ -130,10 +137,10 @@ def _discover_required_extensions(view: FigpackView) -> Set[str]:
130
137
  continue
131
138
 
132
139
  _collect_extensions(view)
133
- return extensions
140
+ return extensions_discovered
134
141
 
135
142
 
136
- def _write_extension_files(extension_names: Set[str], tmpdir: str) -> None:
143
+ def _write_extension_files(extensions, tmpdir: str) -> None:
137
144
  """
138
145
  Write JavaScript files for the required extensions
139
146
 
@@ -141,20 +148,11 @@ def _write_extension_files(extension_names: Set[str], tmpdir: str) -> None:
141
148
  extension_names: Set of extension names to write
142
149
  tmpdir: Directory to write extension files to
143
150
  """
144
- if not extension_names:
145
- return
146
-
147
- registry = ExtensionRegistry.get_instance()
148
151
  tmpdir_path = pathlib.Path(tmpdir)
149
152
 
150
- for extension_name in extension_names:
151
- extension = registry.get_extension(extension_name)
152
- if extension is None:
153
- raise RuntimeError(
154
- f"Extension '{extension_name}' is required but not registered"
155
- )
156
-
157
- # Write the main JavaScript file
153
+ for extension in extensions:
154
+ if not isinstance(extension, FigpackExtension):
155
+ raise ValueError("Expected a FigpackExtension instance")
158
156
  js_filename = extension.get_javascript_filename()
159
157
  js_path = tmpdir_path / js_filename
160
158
 
@@ -164,7 +162,7 @@ def _write_extension_files(extension_names: Set[str], tmpdir: str) -> None:
164
162
  * Version: {extension.version}
165
163
  * Generated automatically - do not edit
166
164
  */
167
-
165
+
168
166
  {extension.javascript_code}
169
167
  """
170
168
 
@@ -187,3 +185,43 @@ def _write_extension_files(extension_names: Set[str], tmpdir: str) -> None:
187
185
  """
188
186
 
189
187
  additional_path.write_text(additional_js_content, encoding="utf-8")
188
+
189
+
190
+ def _write_extension_manifest(extensions, tmpdir: str) -> None:
191
+ """
192
+ Write the extension manifest file that lists all extensions and their files
193
+
194
+ Args:
195
+ extensions: List of FigpackExtension instances
196
+ tmpdir: Directory to write the manifest file to
197
+ """
198
+ tmpdir_path = pathlib.Path(tmpdir)
199
+ manifest_path = tmpdir_path / "extension_manifest.json"
200
+
201
+ # Build the manifest data
202
+ manifest_data = {"extensions": []}
203
+
204
+ for extension in extensions:
205
+ if not isinstance(extension, FigpackExtension):
206
+ raise ValueError("Expected a FigpackExtension instance")
207
+
208
+ # Get the main script filename
209
+ main_script = extension.get_javascript_filename()
210
+
211
+ # Get additional script filenames
212
+ additional_filenames = extension.get_additional_filenames()
213
+ additional_scripts = list(additional_filenames.values())
214
+
215
+ extension_entry = {
216
+ "name": extension.name,
217
+ "mainScript": main_script,
218
+ "additionalScripts": additional_scripts,
219
+ "version": extension.version,
220
+ }
221
+
222
+ manifest_data["extensions"].append(extension_entry)
223
+
224
+ # Write the manifest file
225
+ manifest_path.write_text(
226
+ json.dumps(manifest_data, indent=2, ensure_ascii=False), encoding="utf-8"
227
+ )
@@ -3,7 +3,7 @@ Base class for views that use figpack extensions
3
3
  """
4
4
 
5
5
  from .figpack_view import FigpackView
6
- from .figpack_extension import ExtensionRegistry
6
+ from .figpack_extension import FigpackExtension
7
7
  from ..core.zarr import Group
8
8
 
9
9
 
@@ -12,7 +12,7 @@ class ExtensionView(FigpackView):
12
12
  Base class for views that are rendered by figpack extensions
13
13
  """
14
14
 
15
- def __init__(self, *, extension_name: str):
15
+ def __init__(self, *, extension: FigpackExtension, view_type: str):
16
16
  """
17
17
  Initialize an extension-based view
18
18
 
@@ -20,17 +20,8 @@ class ExtensionView(FigpackView):
20
20
  extension_name: Name of the extension that will render this view
21
21
  """
22
22
  super().__init__()
23
- self.extension_name = extension_name
24
-
25
- # Validate that the extension is registered
26
- registry = ExtensionRegistry.get_instance()
27
- extension = registry.get_extension(extension_name)
28
- if extension is None:
29
- raise ValueError(
30
- f"Extension '{extension_name}' is not registered. "
31
- f"Make sure to register the extension before creating views that use it."
32
- )
33
23
  self.extension = extension
24
+ self.view_type = view_type
34
25
 
35
26
  def _write_to_zarr_group(self, group: Group) -> None:
36
27
  """
@@ -42,18 +33,9 @@ class ExtensionView(FigpackView):
42
33
  group: Zarr group to write data into
43
34
  """
44
35
  # Set the view type to indicate this is an extension view
45
- group.attrs["view_type"] = "ExtensionView"
36
+ group.attrs["view_type"] = self.view_type
46
37
 
47
38
  # Store the extension name so the frontend knows which extension to use
48
- group.attrs["extension_name"] = self.extension_name
49
-
50
- # Store additional script names
51
- group.attrs["additional_script_names"] = list(
52
- self.extension.get_additional_filenames().keys()
53
- )
54
-
55
- # Store extension metadata for debugging/compatibility
56
- registry = ExtensionRegistry.get_instance()
57
- extension = registry.get_extension(self.extension_name)
58
- if extension:
59
- group.attrs["extension_version"] = extension.version
39
+ group.attrs["extension_name"] = self.extension.name
40
+
41
+ group.attrs["extension_version"] = self.extension.version
@@ -64,74 +64,3 @@ class FigpackExtension:
64
64
  original_name: f"extension-{safe_name}-{original_name}"
65
65
  for original_name in self.additional_files.keys()
66
66
  }
67
-
68
-
69
- class ExtensionRegistry:
70
- """
71
- Singleton registry for managing figpack extensions
72
- """
73
-
74
- _instance: Optional["ExtensionRegistry"] = None
75
-
76
- def __init__(self):
77
- self._extensions: Dict[str, FigpackExtension] = {}
78
-
79
- @classmethod
80
- def get_instance(cls) -> "ExtensionRegistry":
81
- """Get the singleton instance of the extension registry"""
82
- if cls._instance is None:
83
- cls._instance = cls()
84
- return cls._instance
85
-
86
- @classmethod
87
- def register(cls, extension: FigpackExtension) -> None:
88
- """
89
- Register an extension with the global registry
90
-
91
- Args:
92
- extension: The extension to register
93
- """
94
- registry = cls.get_instance()
95
- registry._register_extension(extension)
96
-
97
- def _register_extension(self, extension: FigpackExtension) -> None:
98
- """
99
- Internal method to register an extension
100
-
101
- Args:
102
- extension: The extension to register
103
- """
104
- if extension.name in self._extensions:
105
- existing = self._extensions[extension.name]
106
- if existing.version != extension.version:
107
- print(
108
- f"Warning: Replacing extension '{extension.name}' "
109
- f"version {existing.version} with version {extension.version}"
110
- )
111
-
112
- self._extensions[extension.name] = extension
113
-
114
- def get_extension(self, name: str) -> Optional[FigpackExtension]:
115
- """
116
- Get an extension by name
117
-
118
- Args:
119
- name: Name of the extension to retrieve
120
-
121
- Returns:
122
- The extension if found, None otherwise
123
- """
124
- return self._extensions.get(name)
125
-
126
- def get_all_extensions(self) -> Dict[str, FigpackExtension]:
127
- """
128
- Get all registered extensions
129
-
130
- Returns:
131
- Dictionary mapping extension names to extension objects
132
- """
133
- return self._extensions.copy()
134
-
135
- def clear(self) -> None:
136
- """Clear all registered extensions (mainly for testing)"""
137
- self._extensions.clear()