figpack 0.2.15__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.
- figpack/__init__.py +4 -3
- figpack/core/__init__.py +2 -2
- figpack/core/_bundle_utils.py +80 -33
- figpack/core/_view_figure.py +1 -1
- figpack/core/extension_view.py +9 -27
- figpack/core/figpack_extension.py +0 -71
- figpack/core/figpack_view.py +2 -2
- figpack/core/zarr.py +61 -0
- figpack/figpack-figure-dist/assets/index-DBwmtEpB.js +91 -0
- figpack/figpack-figure-dist/assets/{index-D9a3K6eW.css → index-DHWczh-Q.css} +1 -1
- figpack/figpack-figure-dist/index.html +2 -2
- figpack/views/Box.py +2 -3
- figpack/views/DataFrame.py +6 -12
- figpack/views/Gallery.py +2 -3
- figpack/views/Image.py +3 -9
- figpack/views/Markdown.py +3 -4
- figpack/views/MatplotlibFigure.py +2 -11
- figpack/views/MultiChannelTimeseries.py +2 -6
- figpack/views/PlotlyExtension/PlotlyExtension.py +8 -60
- figpack/views/PlotlyExtension/_plotly_extension.py +46 -0
- figpack/views/PlotlyExtension/plotly_view.js +84 -80
- figpack/views/Spectrogram.py +2 -7
- figpack/views/Splitter.py +2 -3
- figpack/views/TabLayout.py +2 -3
- figpack/views/TimeseriesGraph.py +6 -10
- figpack/views/__init__.py +1 -0
- {figpack-0.2.15.dist-info → figpack-0.2.17.dist-info}/METADATA +21 -2
- figpack-0.2.17.dist-info/RECORD +43 -0
- figpack/figpack-figure-dist/assets/index-DtOnN02w.js +0 -846
- figpack/franklab/__init__.py +0 -5
- figpack/franklab/views/TrackAnimation.py +0 -153
- figpack/franklab/views/__init__.py +0 -9
- figpack/spike_sorting/__init__.py +0 -5
- figpack/spike_sorting/views/AutocorrelogramItem.py +0 -32
- figpack/spike_sorting/views/Autocorrelograms.py +0 -118
- figpack/spike_sorting/views/AverageWaveforms.py +0 -147
- figpack/spike_sorting/views/CrossCorrelogramItem.py +0 -35
- figpack/spike_sorting/views/CrossCorrelograms.py +0 -132
- figpack/spike_sorting/views/RasterPlot.py +0 -288
- figpack/spike_sorting/views/RasterPlotItem.py +0 -28
- figpack/spike_sorting/views/SpikeAmplitudes.py +0 -374
- figpack/spike_sorting/views/SpikeAmplitudesItem.py +0 -38
- figpack/spike_sorting/views/UnitMetricsGraph.py +0 -129
- figpack/spike_sorting/views/UnitSimilarityScore.py +0 -40
- figpack/spike_sorting/views/UnitsTable.py +0 -89
- figpack/spike_sorting/views/UnitsTableColumn.py +0 -40
- figpack/spike_sorting/views/UnitsTableRow.py +0 -36
- figpack/spike_sorting/views/__init__.py +0 -41
- figpack-0.2.15.dist-info/RECORD +0 -60
- {figpack-0.2.15.dist-info → figpack-0.2.17.dist-info}/WHEEL +0 -0
- {figpack-0.2.15.dist-info → figpack-0.2.17.dist-info}/entry_points.txt +0 -0
- {figpack-0.2.15.dist-info → figpack-0.2.17.dist-info}/licenses/LICENSE +0 -0
- {figpack-0.2.15.dist-info → figpack-0.2.17.dist-info}/top_level.txt +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
.unitEntryBase{padding-right:13px;padding-top:10px}.unselectedUnitEntry{border:1px transparent solid;font-weight:400;color:#000;background-color:#fff}.selectedUnitEntry{border:1px solid blue;font-weight:700;color:#000;background-color:#b5d1ff}.unitIdsColumnLabelStyle{min-width:200px;font-weight:700;padding:7px 5px}.unitLabelsStyle{padding-right:3px;color:#333}.plotUnitLabel{text-align:left;margin-left:20px;margin-top:5px;font-weight:700}.plotWrapperButtonParent{display:inline-block}.plotWrapperStyleButton{padding-top:50px}.plotUnselectedStyle{border:3px solid rgb(202,224,231)}.plotSelectedStyle{border:3px solid #9999ff;background-color:#fff}.plotUnselectableStyle{border:3px solid transparent}.plotCurrentStyle{border:3px solid blue;background-color:#fff}.plotLabelStyle{font-weight:700;text-align:center;overflow:hidden;white-space:nowrap}:root{font-family:system-ui,Avenir,Helvetica,Arial,sans-serif;line-height:1.5;font-weight:400;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}a{font-weight:500;color:#646cff;text-decoration:inherit}a:hover{color:#535bf2}body{margin:0;overflow:hidden}h1{font-size:3.2em;line-height:1.1}button{border-radius:8px;border:1px solid transparent;padding:.6em 1.2em;font-size:1em;font-weight:500;font-family:inherit;background-color:#1a1a1a;cursor:pointer;transition:border-color .25s}button:hover{border-color:#646cff}button:focus,button:focus-visible{outline:4px auto -webkit-focus-ring-color}.status-bar{position:fixed;bottom:0;left:0;right:0;height:30px;background-color:#2a2a2a;color:#fff;display:flex;align-items:center;padding:0 12px;font-size:12px;border-top:1px solid #444;z-index:1000}.status-bar.warning{background-color:#ff9800;color:#000}.status-bar.error{background-color:#f44336;color:#fff}.status-bar.expired{background-color:#d32f2f;color:#fff}.manage-button{background-color:#444;color:#fff;border:none;padding:4px 8px;border-radius:4px;cursor:pointer;font-size:11px;height:22px;margin-left:12px;transition:background-color .2s}.manage-button:hover{background-color:#666}.about-button{background-color:#444;color:#fff;border:none;padding:4px 8px;border-radius:4px;cursor:pointer;font-size:11px;height:22px;margin-left:12px;transition:background-color .2s}.about-button:hover{background-color:#666}.about-dialog-overlay{position:fixed;inset:0;background-color:#00000080;display:flex;justify-content:center;align-items:center;z-index:2000}.about-dialog{background-color:#2a2a2a;color:#fff;border-radius:8px;max-width:600px;max-height:80vh;width:90%;box-shadow:0 4px 20px #0000004d;overflow:hidden}.about-dialog-header{display:flex;justify-content:space-between;align-items:center;padding:16px 20px;border-bottom:1px solid #444}.about-dialog-header h2{margin:0;font-size:18px;font-weight:600}.about-dialog-close{background:none;border:none;color:#fff;font-size:24px;cursor:pointer;padding:0;width:30px;height:30px;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:background-color .2s}.about-dialog-close:hover{background-color:#444}.about-dialog-content{padding:20px;overflow-y:auto;max-height:calc(80vh - 80px)}.about-dialog-description{line-height:1.6}.about-dialog-description h1,.about-dialog-description h2,.about-dialog-description h3{margin-top:0;margin-bottom:12px}.about-dialog-description p{margin-bottom:12px}.about-dialog-description code{background-color:#444;padding:2px 4px;border-radius:3px;font-family:Courier New,monospace;font-size:.9em}.about-dialog-description pre{background-color:#444;padding:12px;border-radius:4px;overflow-x:auto;margin-bottom:12px}.about-dialog-description ul,.about-dialog-description ol{margin-bottom:12px;padding-left:20px}.about-dialog-description blockquote{border-left:4px solid #666;padding-left:16px;margin:12px 0;font-style:italic}@media (prefers-color-scheme: light){:root{color:#213547;background-color:#fff}a:hover{color:#747bff}button{background-color:#f9f9f9}.status-bar{background-color:#f5f5f5;color:#333;border-top:1px solid #ddd}.status-bar.warning{background-color:#fff3cd;color:#856404;border-top:1px solid #ffeaa7}.status-bar.error,.status-bar.expired{background-color:#f8d7da;color:#721c24;border-top:1px solid #f5c6cb}.manage-button{background-color:#e0e0e0;color:#333;border:1px solid #ccc}.manage-button:hover{background-color:#d0d0d0}.about-button{background-color:#e0e0e0;color:#333;border:1px solid #ccc}.about-button:hover{background-color:#d0d0d0}.about-dialog{background-color:#fff;color:#333;box-shadow:0 4px 20px #00000026}.about-dialog-header{border-bottom:1px solid #ddd}.about-dialog-close{color:#333}.about-dialog-close:hover{background-color:#f0f0f0}.about-dialog-description code,.about-dialog-description pre{background-color:#f5f5f5;color:#333}.about-dialog-description blockquote{border-left:4px solid #ccc}}
|
|
1
|
+
.unitEntryBase{padding-right:13px;padding-top:10px}.unselectedUnitEntry{border:1px transparent solid;font-weight:400;color:#000;background-color:#fff}.selectedUnitEntry{border:1px solid blue;font-weight:700;color:#000;background-color:#b5d1ff}.unitIdsColumnLabelStyle{min-width:200px;font-weight:700;padding:7px 5px}.unitLabelsStyle{padding-right:3px;color:#333}.plotUnitLabel{text-align:left;margin-left:20px;margin-top:5px;font-weight:700}.plotWrapperButtonParent{display:inline-block}.plotWrapperStyleButton{padding-top:50px}.plotUnselectedStyle{border:3px solid rgb(202,224,231)}.plotSelectedStyle{border:3px solid #9999ff;background-color:#fff}.plotUnselectableStyle{border:3px solid transparent}.plotCurrentStyle{border:3px solid blue;background-color:#fff}.plotLabelStyle{font-weight:700;text-align:center;overflow:hidden;white-space:nowrap}:root{font-family:system-ui,Avenir,Helvetica,Arial,sans-serif;line-height:1.5;font-weight:400;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}a{font-weight:500;color:#646cff;text-decoration:inherit}a:hover{color:#535bf2}body{margin:0;overflow:hidden}h1{font-size:3.2em;line-height:1.1}button{border-radius:8px;border:1px solid transparent;padding:.6em 1.2em;font-size:1em;font-weight:500;font-family:inherit;background-color:#1a1a1a;cursor:pointer;transition:border-color .25s}button:hover{border-color:#646cff}button:focus,button:focus-visible{outline:4px auto -webkit-focus-ring-color}.status-bar{position:fixed;bottom:0;left:0;right:0;height:30px;background-color:#2a2a2a;color:#fff;display:flex;align-items:center;padding:0 12px;font-size:12px;border-top:1px solid #444;z-index:1000}.status-bar.warning{background-color:#ff9800;color:#000}.status-bar.error{background-color:#f44336;color:#fff}.status-bar.expired{background-color:#d32f2f;color:#fff}.manage-button{background-color:#444;color:#fff;border:none;padding:4px 8px;border-radius:4px;cursor:pointer;font-size:11px;height:22px;margin-left:12px;transition:background-color .2s}.manage-button:hover{background-color:#666}.about-button{background-color:#444;color:#fff;border:none;padding:4px 8px;border-radius:4px;cursor:pointer;font-size:11px;height:22px;margin-left:12px;transition:background-color .2s}.about-button:hover{background-color:#666}.about-dialog-overlay{position:fixed;inset:0;background-color:#00000080;display:flex;justify-content:center;align-items:center;z-index:2000}.about-dialog{background-color:#2a2a2a;color:#fff;border-radius:8px;max-width:600px;max-height:80vh;width:90%;box-shadow:0 4px 20px #0000004d;overflow:hidden}.about-dialog-header{display:flex;justify-content:space-between;align-items:center;padding:16px 20px;border-bottom:1px solid #444}.about-dialog-header h2{margin:0;font-size:18px;font-weight:600}.about-dialog-close{background:none;border:none;color:#fff;font-size:24px;cursor:pointer;padding:0;width:30px;height:30px;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:background-color .2s}.about-dialog-close:hover{background-color:#444}.about-dialog-content{padding:20px;overflow-y:auto;max-height:calc(80vh - 80px)}.about-dialog-description{line-height:1.6}.about-dialog-description h1,.about-dialog-description h2,.about-dialog-description h3{margin-top:0;margin-bottom:12px}.about-dialog-description p{margin-bottom:12px}.about-dialog-description code{background-color:#444;padding:2px 4px;border-radius:3px;font-family:Courier New,monospace;font-size:.9em}.about-dialog-description pre{background-color:#444;padding:12px;border-radius:4px;overflow-x:auto;margin-bottom:12px}.about-dialog-description ul,.about-dialog-description ol{margin-bottom:12px;padding-left:20px}.about-dialog-description blockquote{border-left:4px solid #666;padding-left:16px;margin:12px 0;font-style:italic}@media (prefers-color-scheme: light){:root{color:#213547;background-color:#fff}a:hover{color:#747bff}button{background-color:#f9f9f9}.status-bar{background-color:#f5f5f5;color:#333;border-top:1px solid #ddd}.status-bar.warning{background-color:#fff3cd;color:#856404;border-top:1px solid #ffeaa7}.status-bar.error,.status-bar.expired{background-color:#f8d7da;color:#721c24;border-top:1px solid #f5c6cb}.manage-button{background-color:#e0e0e0;color:#333;border:1px solid #ccc}.manage-button:hover{background-color:#d0d0d0}.about-button{background-color:#e0e0e0;color:#333;border:1px solid #ccc}.about-button:hover{background-color:#d0d0d0}.about-dialog{background-color:#fff;color:#333;box-shadow:0 4px 20px #00000026}.about-dialog-header{border-bottom:1px solid #ddd}.about-dialog-close{color:#333}.about-dialog-close:hover{background-color:#f0f0f0}.about-dialog-description code,.about-dialog-description pre{background-color:#f5f5f5;color:#333}.about-dialog-description blockquote{border-left:4px solid #ccc}}
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<link rel="icon" type="image/png" href="./assets/neurosift-logo-CLsuwLMO.png" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>figpack figure</title>
|
|
8
|
-
<script type="module" crossorigin src="./assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
8
|
+
<script type="module" crossorigin src="./assets/index-DBwmtEpB.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="./assets/index-DHWczh-Q.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
figpack/views/Box.py
CHANGED
|
@@ -4,9 +4,8 @@ Box view for figpack - a layout container that handles other views
|
|
|
4
4
|
|
|
5
5
|
from typing import Any, Dict, List, Literal, Optional
|
|
6
6
|
|
|
7
|
-
import zarr
|
|
8
|
-
|
|
9
7
|
from ..core.figpack_view import FigpackView
|
|
8
|
+
from ..core.zarr import Group
|
|
10
9
|
from .LayoutItem import LayoutItem
|
|
11
10
|
|
|
12
11
|
|
|
@@ -43,7 +42,7 @@ class Box(FigpackView):
|
|
|
43
42
|
self.items = items
|
|
44
43
|
self.title = title
|
|
45
44
|
|
|
46
|
-
def _write_to_zarr_group(self, group:
|
|
45
|
+
def _write_to_zarr_group(self, group: Group) -> None:
|
|
47
46
|
"""
|
|
48
47
|
Write the Box layout data to a Zarr group
|
|
49
48
|
|
figpack/views/DataFrame.py
CHANGED
|
@@ -3,13 +3,12 @@ DataFrame view for figpack - displays pandas DataFrames as interactive tables
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
|
-
from typing import Any, Dict, Union
|
|
7
6
|
|
|
8
7
|
import numpy as np
|
|
9
|
-
import pandas as pd
|
|
10
8
|
import zarr
|
|
11
9
|
|
|
12
10
|
from ..core.figpack_view import FigpackView
|
|
11
|
+
from ..core.zarr import Group
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
class DataFrame(FigpackView):
|
|
@@ -17,7 +16,7 @@ class DataFrame(FigpackView):
|
|
|
17
16
|
A DataFrame visualization component for displaying pandas DataFrames as interactive tables
|
|
18
17
|
"""
|
|
19
18
|
|
|
20
|
-
def __init__(self, df
|
|
19
|
+
def __init__(self, df):
|
|
21
20
|
"""
|
|
22
21
|
Initialize a DataFrame view
|
|
23
22
|
|
|
@@ -27,12 +26,14 @@ class DataFrame(FigpackView):
|
|
|
27
26
|
Raises:
|
|
28
27
|
ValueError: If df is not a pandas DataFrame
|
|
29
28
|
"""
|
|
29
|
+
import pandas as pd
|
|
30
|
+
|
|
30
31
|
if not isinstance(df, pd.DataFrame):
|
|
31
32
|
raise ValueError("df must be a pandas DataFrame")
|
|
32
33
|
|
|
33
34
|
self.df = df
|
|
34
35
|
|
|
35
|
-
def _write_to_zarr_group(self, group:
|
|
36
|
+
def _write_to_zarr_group(self, group: Group) -> None:
|
|
36
37
|
"""
|
|
37
38
|
Write the DataFrame data to a Zarr group
|
|
38
39
|
|
|
@@ -54,11 +55,6 @@ class DataFrame(FigpackView):
|
|
|
54
55
|
group.create_dataset(
|
|
55
56
|
"csv_data",
|
|
56
57
|
data=csv_array,
|
|
57
|
-
dtype=np.uint8,
|
|
58
|
-
chunks=True,
|
|
59
|
-
compressor=zarr.Blosc(
|
|
60
|
-
cname="zstd", clevel=3, shuffle=zarr.Blosc.SHUFFLE
|
|
61
|
-
),
|
|
62
58
|
)
|
|
63
59
|
|
|
64
60
|
# Store metadata about the DataFrame
|
|
@@ -104,6 +100,4 @@ class DataFrame(FigpackView):
|
|
|
104
100
|
group.attrs["data_size"] = 0
|
|
105
101
|
group.attrs["column_info"] = "[]"
|
|
106
102
|
# Create empty array as placeholder
|
|
107
|
-
group.create_dataset(
|
|
108
|
-
"csv_data", data=np.array([], dtype=np.uint8), dtype=np.uint8
|
|
109
|
-
)
|
|
103
|
+
group.create_dataset("csv_data", data=np.array([], dtype=np.uint8))
|
figpack/views/Gallery.py
CHANGED
|
@@ -4,9 +4,8 @@ Gallery view for figpack - a gallery layout container that handles other views w
|
|
|
4
4
|
|
|
5
5
|
from typing import Any, Dict, List, Optional
|
|
6
6
|
|
|
7
|
-
import zarr
|
|
8
|
-
|
|
9
7
|
from ..core.figpack_view import FigpackView
|
|
8
|
+
from ..core.zarr import Group
|
|
10
9
|
from .GalleryItem import GalleryItem
|
|
11
10
|
|
|
12
11
|
|
|
@@ -45,7 +44,7 @@ class Gallery(FigpackView):
|
|
|
45
44
|
max(0, min(initial_item_index, len(items) - 1)) if items else 0
|
|
46
45
|
)
|
|
47
46
|
|
|
48
|
-
def _write_to_zarr_group(self, group:
|
|
47
|
+
def _write_to_zarr_group(self, group: Group) -> None:
|
|
49
48
|
"""
|
|
50
49
|
Write the Gallery data to a Zarr group
|
|
51
50
|
|
figpack/views/Image.py
CHANGED
|
@@ -8,6 +8,7 @@ import numpy as np
|
|
|
8
8
|
import zarr
|
|
9
9
|
|
|
10
10
|
from ..core.figpack_view import FigpackView
|
|
11
|
+
from ..core.zarr import Group
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class Image(FigpackView):
|
|
@@ -69,7 +70,7 @@ class Image(FigpackView):
|
|
|
69
70
|
except Exception as e:
|
|
70
71
|
raise ValueError(f"Failed to download image from URL: {str(e)}")
|
|
71
72
|
|
|
72
|
-
def _write_to_zarr_group(self, group:
|
|
73
|
+
def _write_to_zarr_group(self, group: Group) -> None:
|
|
73
74
|
"""
|
|
74
75
|
Write the image data to a Zarr group
|
|
75
76
|
|
|
@@ -98,11 +99,6 @@ class Image(FigpackView):
|
|
|
98
99
|
group.create_dataset(
|
|
99
100
|
"image_data",
|
|
100
101
|
data=image_array,
|
|
101
|
-
dtype=np.uint8,
|
|
102
|
-
chunks=True,
|
|
103
|
-
compressor=zarr.Blosc(
|
|
104
|
-
cname="zstd", clevel=3, shuffle=zarr.Blosc.SHUFFLE
|
|
105
|
-
),
|
|
106
102
|
)
|
|
107
103
|
|
|
108
104
|
# Try to determine format from file signature
|
|
@@ -124,6 +120,4 @@ class Image(FigpackView):
|
|
|
124
120
|
group.attrs["image_format"] = "Unknown"
|
|
125
121
|
group.attrs["data_size"] = 0
|
|
126
122
|
# Create empty array as placeholder
|
|
127
|
-
group.create_dataset(
|
|
128
|
-
"image_data", data=np.array([], dtype=np.uint8), dtype=np.uint8
|
|
129
|
-
)
|
|
123
|
+
group.create_dataset("image_data", data=np.array([], dtype=np.uint8))
|
figpack/views/Markdown.py
CHANGED
|
@@ -6,6 +6,7 @@ import numpy as np
|
|
|
6
6
|
import zarr
|
|
7
7
|
|
|
8
8
|
from ..core.figpack_view import FigpackView
|
|
9
|
+
from ..core.zarr import Group
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class Markdown(FigpackView):
|
|
@@ -22,7 +23,7 @@ class Markdown(FigpackView):
|
|
|
22
23
|
"""
|
|
23
24
|
self.content = content
|
|
24
25
|
|
|
25
|
-
def _write_to_zarr_group(self, group:
|
|
26
|
+
def _write_to_zarr_group(self, group: Group) -> None:
|
|
26
27
|
"""
|
|
27
28
|
Write the markdown data to a Zarr group
|
|
28
29
|
|
|
@@ -37,9 +38,7 @@ class Markdown(FigpackView):
|
|
|
37
38
|
content_array = np.frombuffer(content_bytes, dtype=np.uint8)
|
|
38
39
|
|
|
39
40
|
# Store the markdown content as a zarr array
|
|
40
|
-
group.create_dataset(
|
|
41
|
-
"content_data", data=content_array, dtype=np.uint8, chunks=True
|
|
42
|
-
)
|
|
41
|
+
group.create_dataset("content_data", data=content_array, chunks=True)
|
|
43
42
|
|
|
44
43
|
# Store content size in attrs
|
|
45
44
|
group.attrs["data_size"] = len(content_bytes)
|
|
@@ -9,6 +9,7 @@ from typing import Any, Union
|
|
|
9
9
|
import zarr
|
|
10
10
|
|
|
11
11
|
from ..core.figpack_view import FigpackView
|
|
12
|
+
from ..core.zarr import Group
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class MatplotlibFigure(FigpackView):
|
|
@@ -25,7 +26,7 @@ class MatplotlibFigure(FigpackView):
|
|
|
25
26
|
"""
|
|
26
27
|
self.fig = fig
|
|
27
28
|
|
|
28
|
-
def _write_to_zarr_group(self, group:
|
|
29
|
+
def _write_to_zarr_group(self, group: Group) -> None:
|
|
29
30
|
"""
|
|
30
31
|
Write the matplotlib figure data to a Zarr group
|
|
31
32
|
|
|
@@ -54,11 +55,6 @@ class MatplotlibFigure(FigpackView):
|
|
|
54
55
|
group.create_dataset(
|
|
55
56
|
"svg_data",
|
|
56
57
|
data=svg_array,
|
|
57
|
-
dtype=np.uint8,
|
|
58
|
-
chunks=True,
|
|
59
|
-
compressor=zarr.Blosc(
|
|
60
|
-
cname="zstd", clevel=3, shuffle=zarr.Blosc.SHUFFLE
|
|
61
|
-
),
|
|
62
58
|
)
|
|
63
59
|
|
|
64
60
|
# Store figure dimensions for reference
|
|
@@ -77,11 +73,6 @@ class MatplotlibFigure(FigpackView):
|
|
|
77
73
|
group.create_dataset(
|
|
78
74
|
"svg_data",
|
|
79
75
|
data=np.array([], dtype=np.uint8),
|
|
80
|
-
dtype=np.uint8,
|
|
81
|
-
chunks=True,
|
|
82
|
-
compressor=zarr.Blosc(
|
|
83
|
-
cname="zstd", clevel=3, shuffle=zarr.Blosc.SHUFFLE
|
|
84
|
-
),
|
|
85
76
|
)
|
|
86
77
|
group.attrs["error"] = f"Failed to export matplotlib figure: {str(e)}"
|
|
87
78
|
group.attrs["figure_width_inches"] = 6.0
|
|
@@ -6,9 +6,9 @@ import math
|
|
|
6
6
|
from typing import List, Optional, Union
|
|
7
7
|
|
|
8
8
|
import numpy as np
|
|
9
|
-
import zarr
|
|
10
9
|
|
|
11
10
|
from ..core.figpack_view import FigpackView
|
|
11
|
+
from ..core.zarr import Group
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class MultiChannelTimeseries(FigpackView):
|
|
@@ -174,7 +174,7 @@ class MultiChannelTimeseries(FigpackView):
|
|
|
174
174
|
else: # len(shape) == 3
|
|
175
175
|
return (chunk_timepoints, 2, n_channels)
|
|
176
176
|
|
|
177
|
-
def _write_to_zarr_group(self, group:
|
|
177
|
+
def _write_to_zarr_group(self, group: Group) -> None:
|
|
178
178
|
"""
|
|
179
179
|
Write the multi-channel timeseries data to a Zarr group
|
|
180
180
|
|
|
@@ -198,8 +198,6 @@ class MultiChannelTimeseries(FigpackView):
|
|
|
198
198
|
"data",
|
|
199
199
|
data=self.data,
|
|
200
200
|
chunks=original_chunks,
|
|
201
|
-
compression="blosc",
|
|
202
|
-
compression_opts={"cname": "lz4", "clevel": 5, "shuffle": 1},
|
|
203
201
|
)
|
|
204
202
|
|
|
205
203
|
# Store downsampled data arrays
|
|
@@ -216,8 +214,6 @@ class MultiChannelTimeseries(FigpackView):
|
|
|
216
214
|
dataset_name,
|
|
217
215
|
data=downsampled_array,
|
|
218
216
|
chunks=ds_chunks,
|
|
219
|
-
compression="blosc",
|
|
220
|
-
compression_opts={"cname": "lz4", "clevel": 5, "shuffle": 1},
|
|
221
217
|
)
|
|
222
218
|
|
|
223
219
|
print(
|
|
@@ -1,58 +1,11 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import numpy as np
|
|
3
|
-
import zarr
|
|
4
|
-
import urllib.request
|
|
5
|
-
import urllib.error
|
|
6
3
|
from datetime import date, datetime
|
|
7
4
|
|
|
8
|
-
|
|
5
|
+
import figpack
|
|
9
6
|
|
|
10
7
|
|
|
11
|
-
|
|
12
|
-
url = "https://cdn.plot.ly/plotly-2.35.2.min.js"
|
|
13
|
-
try:
|
|
14
|
-
with urllib.request.urlopen(url) as response:
|
|
15
|
-
return response.read().decode("utf-8")
|
|
16
|
-
except urllib.error.URLError as e:
|
|
17
|
-
raise RuntimeError(f"Failed to download plotly library from {url}: {e}")
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def _load_javascript_code():
|
|
21
|
-
"""Load the JavaScript code from the plotly.js file"""
|
|
22
|
-
import os
|
|
23
|
-
|
|
24
|
-
js_path = os.path.join(os.path.dirname(__file__), "plotly_view.js")
|
|
25
|
-
try:
|
|
26
|
-
with open(js_path, "r", encoding="utf-8") as f:
|
|
27
|
-
return f.read()
|
|
28
|
-
except FileNotFoundError:
|
|
29
|
-
raise FileNotFoundError(
|
|
30
|
-
f"Could not find plotly.js at {js_path}. "
|
|
31
|
-
"Make sure the JavaScript file is present in the package."
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
# Download the plotly library and create the extension with additional files
|
|
36
|
-
try:
|
|
37
|
-
plotly_lib_js = _download_plotly_library()
|
|
38
|
-
additional_files = {"plotly.min.js": plotly_lib_js}
|
|
39
|
-
except Exception as e:
|
|
40
|
-
print(f"Warning: Could not download plotly library: {e}")
|
|
41
|
-
print("Extension will fall back to CDN loading")
|
|
42
|
-
additional_files = {}
|
|
43
|
-
|
|
44
|
-
# Create and register the plotly extension
|
|
45
|
-
_plotly_extension = FigpackExtension(
|
|
46
|
-
name="figpack_plotly",
|
|
47
|
-
javascript_code=_load_javascript_code(),
|
|
48
|
-
additional_files=additional_files,
|
|
49
|
-
version="1.0.0",
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
ExtensionRegistry.register(_plotly_extension)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
class PlotlyFigure(ExtensionView):
|
|
8
|
+
class PlotlyFigure(figpack.ExtensionView):
|
|
56
9
|
"""
|
|
57
10
|
A Plotly graph visualization view using the plotly library.
|
|
58
11
|
|
|
@@ -66,13 +19,14 @@ class PlotlyFigure(ExtensionView):
|
|
|
66
19
|
Args:
|
|
67
20
|
fig: The plotly figure object
|
|
68
21
|
"""
|
|
69
|
-
#
|
|
70
|
-
|
|
71
|
-
|
|
22
|
+
# It's important that we only import conditionally, so we are not always downloading plotly
|
|
23
|
+
from ._plotly_extension import _plotly_extension
|
|
24
|
+
|
|
25
|
+
super().__init__(extension=_plotly_extension, view_type="plotly.PlotlyFigure")
|
|
72
26
|
|
|
73
27
|
self.fig = fig
|
|
74
28
|
|
|
75
|
-
def _write_to_zarr_group(self, group:
|
|
29
|
+
def _write_to_zarr_group(self, group: figpack.Group) -> None:
|
|
76
30
|
"""
|
|
77
31
|
Write the plotly figure data to a Zarr group
|
|
78
32
|
|
|
@@ -92,13 +46,7 @@ class PlotlyFigure(ExtensionView):
|
|
|
92
46
|
json_array = np.frombuffer(json_bytes, dtype=np.uint8)
|
|
93
47
|
|
|
94
48
|
# Store the figure data as compressed array
|
|
95
|
-
group.create_dataset(
|
|
96
|
-
"figure_data",
|
|
97
|
-
data=json_array,
|
|
98
|
-
dtype=np.uint8,
|
|
99
|
-
chunks=True,
|
|
100
|
-
compressor=zarr.Blosc(cname="zstd", clevel=3, shuffle=zarr.Blosc.SHUFFLE),
|
|
101
|
-
)
|
|
49
|
+
group.create_dataset("figure_data", data=json_array)
|
|
102
50
|
|
|
103
51
|
# Store data size for reference
|
|
104
52
|
group.attrs["data_size"] = len(json_bytes)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import urllib.request
|
|
2
|
+
import urllib.error
|
|
3
|
+
|
|
4
|
+
from ...core.figpack_extension import FigpackExtension
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _load_javascript_code():
|
|
8
|
+
"""Load the JavaScript code from the plotly.js file"""
|
|
9
|
+
import os
|
|
10
|
+
|
|
11
|
+
js_path = os.path.join(os.path.dirname(__file__), "plotly_view.js")
|
|
12
|
+
try:
|
|
13
|
+
with open(js_path, "r", encoding="utf-8") as f:
|
|
14
|
+
return f.read()
|
|
15
|
+
except FileNotFoundError:
|
|
16
|
+
raise FileNotFoundError(
|
|
17
|
+
f"Could not find plotly.js at {js_path}. "
|
|
18
|
+
"Make sure the JavaScript file is present in the package."
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _download_plotly_library():
|
|
23
|
+
url = "https://cdn.plot.ly/plotly-2.35.2.min.js"
|
|
24
|
+
try:
|
|
25
|
+
with urllib.request.urlopen(url) as response:
|
|
26
|
+
return response.read().decode("utf-8")
|
|
27
|
+
except urllib.error.URLError as e:
|
|
28
|
+
raise RuntimeError(f"Failed to download plotly library from {url}: {e}")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# Download the plotly library and create the extension with additional files
|
|
32
|
+
try:
|
|
33
|
+
plotly_lib_js = _download_plotly_library()
|
|
34
|
+
additional_files = {"plotly.min.js": plotly_lib_js}
|
|
35
|
+
except Exception as e:
|
|
36
|
+
print(f"Warning: Could not download plotly library: {e}")
|
|
37
|
+
print("Extension will fall back to CDN loading")
|
|
38
|
+
additional_files = {}
|
|
39
|
+
|
|
40
|
+
# Create and register the plotly extension
|
|
41
|
+
_plotly_extension = FigpackExtension(
|
|
42
|
+
name="figpack-plotly",
|
|
43
|
+
javascript_code=_load_javascript_code(),
|
|
44
|
+
additional_files=additional_files,
|
|
45
|
+
version="1.0.0",
|
|
46
|
+
)
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
const loadFigureData = async (zarrGroup) => {
|
|
7
7
|
// Get the figure data from the zarr array
|
|
8
|
-
const data = await zarrGroup.
|
|
9
|
-
|
|
8
|
+
const data = await zarrGroup.getDatasetData(
|
|
9
|
+
"figure_data",
|
|
10
10
|
{},
|
|
11
11
|
);
|
|
12
12
|
if (!data || data.length === 0) {
|
|
@@ -24,83 +24,87 @@ const loadFigureData = async (zarrGroup) => {
|
|
|
24
24
|
return parsedData;
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
-
(
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return {
|
|
63
|
-
destroy: () => {
|
|
64
|
-
window.Plotly.purge(container);
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
} catch (error) {
|
|
69
|
-
console.error('Error rendering plotly figure:', error);
|
|
70
|
-
this.renderError(container, width, height, error.message);
|
|
71
|
-
return { destroy: () => {} };
|
|
27
|
+
const renderPlotlyFigure = async (params) => {
|
|
28
|
+
const { container, zarrGroup, width, height, onResize } = params;
|
|
29
|
+
container.innerHTML = "";
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const figureData = await loadFigureData(zarrGroup);
|
|
33
|
+
|
|
34
|
+
const makePlot = () => {
|
|
35
|
+
window.Plotly.newPlot(
|
|
36
|
+
container,
|
|
37
|
+
figureData.data || [],
|
|
38
|
+
{
|
|
39
|
+
...figureData.layout,
|
|
40
|
+
width: width,
|
|
41
|
+
height: height,
|
|
42
|
+
margin: { l: 50, r: 50, t: 50, b: 50 },
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
responsive: true,
|
|
46
|
+
displayModeBar: true,
|
|
47
|
+
displaylogo: false,
|
|
48
|
+
},
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
makePlot();
|
|
53
|
+
|
|
54
|
+
// Handle resize events
|
|
55
|
+
onResize((newWidth, newHeight) => {
|
|
56
|
+
window.Plotly.relayout(container, { width: newWidth, height: newHeight });
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
destroy: () => {
|
|
61
|
+
window.Plotly.purge(container);
|
|
72
62
|
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
display: flex;
|
|
81
|
-
align-items: center;
|
|
82
|
-
justify-content: center;
|
|
83
|
-
background-color: #f8f9fa;
|
|
84
|
-
border: 1px solid #dee2e6;
|
|
85
|
-
color: #6c757d;
|
|
86
|
-
font-family: system-ui, -apple-system, sans-serif;
|
|
87
|
-
font-size: 14px;
|
|
88
|
-
text-align: center;
|
|
89
|
-
padding: 20px;
|
|
90
|
-
box-sizing: border-box;
|
|
91
|
-
">
|
|
92
|
-
<div>
|
|
93
|
-
<div style="margin-bottom: 10px; font-weight: 500;">Force Graph Error</div>
|
|
94
|
-
<div style="font-size: 12px;">${message}</div>
|
|
95
|
-
</div>
|
|
96
|
-
</div>
|
|
97
|
-
`;
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
})();
|
|
101
|
-
|
|
102
|
-
const joinPath = function(p1, p2) {
|
|
103
|
-
if (p1.endsWith('/')) p1 = p1.slice(0, -1);
|
|
104
|
-
if (p2.startsWith('/')) p2 = p2.slice(1);
|
|
105
|
-
return p1 + '/' + p2;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error('Error rendering plotly figure:', error);
|
|
67
|
+
renderError(container, width, height, error.message);
|
|
68
|
+
return { destroy: () => {} };
|
|
69
|
+
}
|
|
106
70
|
};
|
|
71
|
+
|
|
72
|
+
const renderError = (container, width, height, message) => {
|
|
73
|
+
container.innerHTML = `
|
|
74
|
+
<div style="
|
|
75
|
+
width: ${width}px;
|
|
76
|
+
height: ${height}px;
|
|
77
|
+
display: flex;
|
|
78
|
+
align-items: center;
|
|
79
|
+
justify-content: center;
|
|
80
|
+
background-color: #f8f9fa;
|
|
81
|
+
border: 1px solid #dee2e6;
|
|
82
|
+
color: #6c757d;
|
|
83
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
84
|
+
font-size: 14px;
|
|
85
|
+
text-align: center;
|
|
86
|
+
padding: 20px;
|
|
87
|
+
box-sizing: border-box;
|
|
88
|
+
">
|
|
89
|
+
<div>
|
|
90
|
+
<div style="margin-bottom: 10px; font-weight: 500;">Plotly Figure Error</div>
|
|
91
|
+
<div style="font-size: 12px;">${message}</div>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
`;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const registerExtension = () => {
|
|
98
|
+
const registerFPViewComponent = window.figpack_p1.registerFPViewComponent;
|
|
99
|
+
registerFPViewComponent({
|
|
100
|
+
name: "plotly.PlotlyFigure",
|
|
101
|
+
render: renderPlotlyFigure,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// const registerFPViewContextCreator = window.figpack_p1.registerFPViewContextCreator;
|
|
105
|
+
|
|
106
|
+
const registerFPExtension = window.figpack_p1.registerFPExtension;
|
|
107
|
+
registerFPExtension({ name: "figpack-plotly" });
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
registerExtension();
|
figpack/views/Spectrogram.py
CHANGED
|
@@ -9,6 +9,7 @@ import numpy as np
|
|
|
9
9
|
import zarr
|
|
10
10
|
|
|
11
11
|
from ..core.figpack_view import FigpackView
|
|
12
|
+
from ..core.zarr import Group
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class Spectrogram(FigpackView):
|
|
@@ -185,7 +186,7 @@ class Spectrogram(FigpackView):
|
|
|
185
186
|
|
|
186
187
|
return (chunk_timepoints, n_frequencies)
|
|
187
188
|
|
|
188
|
-
def _write_to_zarr_group(self, group:
|
|
189
|
+
def _write_to_zarr_group(self, group: Group) -> None:
|
|
189
190
|
"""
|
|
190
191
|
Write the spectrogram data to a Zarr group
|
|
191
192
|
|
|
@@ -212,8 +213,6 @@ class Spectrogram(FigpackView):
|
|
|
212
213
|
group.create_dataset(
|
|
213
214
|
"frequencies",
|
|
214
215
|
data=self.frequencies,
|
|
215
|
-
compression="blosc",
|
|
216
|
-
compression_opts={"cname": "lz4", "clevel": 5, "shuffle": 1},
|
|
217
216
|
)
|
|
218
217
|
|
|
219
218
|
# Store original data with optimal chunking
|
|
@@ -222,8 +221,6 @@ class Spectrogram(FigpackView):
|
|
|
222
221
|
"data",
|
|
223
222
|
data=self.data,
|
|
224
223
|
chunks=original_chunks,
|
|
225
|
-
compression="blosc",
|
|
226
|
-
compression_opts={"cname": "lz4", "clevel": 5, "shuffle": 1},
|
|
227
224
|
)
|
|
228
225
|
|
|
229
226
|
# Store downsampled data arrays
|
|
@@ -240,8 +237,6 @@ class Spectrogram(FigpackView):
|
|
|
240
237
|
dataset_name,
|
|
241
238
|
data=downsampled_array,
|
|
242
239
|
chunks=ds_chunks,
|
|
243
|
-
compression="blosc",
|
|
244
|
-
compression_opts={"cname": "lz4", "clevel": 5, "shuffle": 1},
|
|
245
240
|
)
|
|
246
241
|
|
|
247
242
|
print(f"Stored Spectrogram with {len(downsample_factors)} downsampled levels:")
|
figpack/views/Splitter.py
CHANGED
|
@@ -4,9 +4,8 @@ Splitter view for figpack - a resizable split layout container
|
|
|
4
4
|
|
|
5
5
|
from typing import Literal
|
|
6
6
|
|
|
7
|
-
import zarr
|
|
8
|
-
|
|
9
7
|
from ..core.figpack_view import FigpackView
|
|
8
|
+
from ..core.zarr import Group
|
|
10
9
|
from .LayoutItem import LayoutItem
|
|
11
10
|
|
|
12
11
|
|
|
@@ -37,7 +36,7 @@ class Splitter(FigpackView):
|
|
|
37
36
|
self.item2 = item2
|
|
38
37
|
self.split_pos = max(0.1, min(0.9, split_pos)) # Clamp between 0.1 and 0.9
|
|
39
38
|
|
|
40
|
-
def _write_to_zarr_group(self, group:
|
|
39
|
+
def _write_to_zarr_group(self, group: Group) -> None:
|
|
41
40
|
"""
|
|
42
41
|
Write the Splitter layout data to a Zarr group
|
|
43
42
|
|