figpack 0.2.27__py3-none-any.whl → 0.2.29__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.
Potentially problematic release.
This version of figpack might be problematic. Click here for more details.
- figpack/__init__.py +1 -1
- figpack/core/figpack_view.py +6 -0
- figpack/figpack-figure-dist/assets/index-CSkROe6e.js +392 -0
- figpack/figpack-figure-dist/index.html +1 -1
- figpack/views/Iframe.py +43 -0
- figpack/views/Markdown.py +6 -2
- figpack/views/TimeseriesGraph.py +68 -3
- figpack/views/__init__.py +1 -0
- {figpack-0.2.27.dist-info → figpack-0.2.29.dist-info}/METADATA +1 -1
- {figpack-0.2.27.dist-info → figpack-0.2.29.dist-info}/RECORD +14 -13
- figpack/figpack-figure-dist/assets/index-DnHZdWys.js +0 -95
- {figpack-0.2.27.dist-info → figpack-0.2.29.dist-info}/WHEEL +0 -0
- {figpack-0.2.27.dist-info → figpack-0.2.29.dist-info}/entry_points.txt +0 -0
- {figpack-0.2.27.dist-info → figpack-0.2.29.dist-info}/licenses/LICENSE +0 -0
- {figpack-0.2.27.dist-info → figpack-0.2.29.dist-info}/top_level.txt +0 -0
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// Allow script injection from trusted domains (see src/main.tsx)
|
|
10
10
|
window.script_injection_allowed_domains = ['https://manage.figpack.org', 'https://figpack.org'];
|
|
11
11
|
</script>
|
|
12
|
-
<script type="module" crossorigin src="./assets/index-
|
|
12
|
+
<script type="module" crossorigin src="./assets/index-CSkROe6e.js"></script>
|
|
13
13
|
<link rel="stylesheet" crossorigin href="./assets/index-V5m_wCvw.css">
|
|
14
14
|
</head>
|
|
15
15
|
<body>
|
figpack/views/Iframe.py
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Iframe view for figpack - displays content in an iframe
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from ..core.figpack_view import FigpackView
|
|
8
|
+
from ..core.zarr import Group
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Iframe(FigpackView):
|
|
12
|
+
"""
|
|
13
|
+
An iframe visualization component for displaying web content
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, url: str):
|
|
17
|
+
"""
|
|
18
|
+
Initialize an Iframe view
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
url: The URL to display in the iframe
|
|
22
|
+
"""
|
|
23
|
+
self.url = url
|
|
24
|
+
|
|
25
|
+
def write_to_zarr_group(self, group: Group) -> None:
|
|
26
|
+
"""
|
|
27
|
+
Write the iframe data to a Zarr group
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
group: Zarr group to write data into
|
|
31
|
+
"""
|
|
32
|
+
# Set the view type
|
|
33
|
+
group.attrs["view_type"] = "Iframe"
|
|
34
|
+
|
|
35
|
+
# Convert URL to numpy array of bytes
|
|
36
|
+
url_bytes = self.url.encode("utf-8")
|
|
37
|
+
url_array = np.frombuffer(url_bytes, dtype=np.uint8)
|
|
38
|
+
|
|
39
|
+
# Store the URL as a zarr array
|
|
40
|
+
group.create_dataset("url_data", data=url_array, chunks=True)
|
|
41
|
+
|
|
42
|
+
# Store URL size in attrs
|
|
43
|
+
group.attrs["data_size"] = len(url_bytes)
|
figpack/views/Markdown.py
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
Markdown view for figpack - displays markdown content
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
from typing import Optional
|
|
5
6
|
import numpy as np
|
|
6
|
-
import zarr
|
|
7
7
|
|
|
8
8
|
from ..core.figpack_view import FigpackView
|
|
9
9
|
from ..core.zarr import Group
|
|
@@ -14,7 +14,7 @@ class Markdown(FigpackView):
|
|
|
14
14
|
A markdown content visualization component
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
|
-
def __init__(self, content: str):
|
|
17
|
+
def __init__(self, content: str, *, font_size: Optional[int] = None):
|
|
18
18
|
"""
|
|
19
19
|
Initialize a Markdown view
|
|
20
20
|
|
|
@@ -22,6 +22,7 @@ class Markdown(FigpackView):
|
|
|
22
22
|
content: The markdown content to display
|
|
23
23
|
"""
|
|
24
24
|
self.content = content
|
|
25
|
+
self.font_size = font_size
|
|
25
26
|
|
|
26
27
|
def write_to_zarr_group(self, group: Group) -> None:
|
|
27
28
|
"""
|
|
@@ -33,6 +34,9 @@ class Markdown(FigpackView):
|
|
|
33
34
|
# Set the view type
|
|
34
35
|
group.attrs["view_type"] = "Markdown"
|
|
35
36
|
|
|
37
|
+
if self.font_size is not None:
|
|
38
|
+
group.attrs["font_size"] = self.font_size
|
|
39
|
+
|
|
36
40
|
# Convert string content to numpy array of bytes
|
|
37
41
|
content_bytes = self.content.encode("utf-8")
|
|
38
42
|
content_array = np.frombuffer(content_bytes, dtype=np.uint8)
|
figpack/views/TimeseriesGraph.py
CHANGED
|
@@ -71,6 +71,13 @@ class TimeseriesGraph(FigpackView):
|
|
|
71
71
|
width: Line width
|
|
72
72
|
dash: Dash pattern as [dash_length, gap_length]
|
|
73
73
|
"""
|
|
74
|
+
if isinstance(t, list):
|
|
75
|
+
t = np.array(t)
|
|
76
|
+
if isinstance(y, list):
|
|
77
|
+
y = np.array(y)
|
|
78
|
+
assert t.ndim == 1, "Time array must be 1-dimensional"
|
|
79
|
+
assert y.ndim == 1, "Y array must be 1-dimensional"
|
|
80
|
+
assert len(t) == len(y), "Time and Y arrays must have the same length"
|
|
74
81
|
self._series.append(
|
|
75
82
|
TGLineSeries(name=name, t=t, y=y, color=color, width=width, dash=dash)
|
|
76
83
|
)
|
|
@@ -96,6 +103,13 @@ class TimeseriesGraph(FigpackView):
|
|
|
96
103
|
radius: Marker radius
|
|
97
104
|
shape: Marker shape ("circle", "square", etc.)
|
|
98
105
|
"""
|
|
106
|
+
if isinstance(t, list):
|
|
107
|
+
t = np.array(t)
|
|
108
|
+
if isinstance(y, list):
|
|
109
|
+
y = np.array(y)
|
|
110
|
+
assert t.ndim == 1, "Time array must be 1-dimensional"
|
|
111
|
+
assert y.ndim == 1, "Y array must be 1-dimensional"
|
|
112
|
+
assert len(t) == len(y), "Time and Y arrays must have the same length"
|
|
99
113
|
self._series.append(
|
|
100
114
|
TGMarkerSeries(name=name, t=t, y=y, color=color, radius=radius, shape=shape)
|
|
101
115
|
)
|
|
@@ -119,6 +133,18 @@ class TimeseriesGraph(FigpackView):
|
|
|
119
133
|
color: Fill color
|
|
120
134
|
alpha: Transparency (0-1)
|
|
121
135
|
"""
|
|
136
|
+
if isinstance(t_start, list):
|
|
137
|
+
t_start = np.array(t_start)
|
|
138
|
+
if isinstance(t_end, list):
|
|
139
|
+
t_end = np.array(t_end)
|
|
140
|
+
assert t_start.ndim == 1, "Start time array must be 1-dimensional"
|
|
141
|
+
assert t_end.ndim == 1, "End time array must be 1-dimensional"
|
|
142
|
+
assert len(t_start) == len(
|
|
143
|
+
t_end
|
|
144
|
+
), "Start and end time arrays must have the same length"
|
|
145
|
+
assert np.all(
|
|
146
|
+
t_start <= t_end
|
|
147
|
+
), "Start times must be less than or equal to end times"
|
|
122
148
|
self._series.append(
|
|
123
149
|
TGIntervalSeries(
|
|
124
150
|
name=name, t_start=t_start, t_end=t_end, color=color, alpha=alpha
|
|
@@ -137,6 +163,7 @@ class TimeseriesGraph(FigpackView):
|
|
|
137
163
|
width: float = 1.0,
|
|
138
164
|
channel_spacing: Optional[float] = None,
|
|
139
165
|
auto_channel_spacing: Optional[float] = None,
|
|
166
|
+
timestamps_for_inserting_nans: Optional[np.ndarray] = None,
|
|
140
167
|
) -> None:
|
|
141
168
|
"""
|
|
142
169
|
Add a uniform timeseries to the graph with optional multi-channel support
|
|
@@ -151,7 +178,10 @@ class TimeseriesGraph(FigpackView):
|
|
|
151
178
|
width: Line width
|
|
152
179
|
channel_spacing: Vertical spacing between channels
|
|
153
180
|
auto_channel_spacing: sets channel spacing to this multiple of the estimated RMS noise level
|
|
181
|
+
timestamps_for_inserting_nans: Optional array of timestamps used to determine where to insert NaNs in the data
|
|
154
182
|
"""
|
|
183
|
+
if isinstance(data, list):
|
|
184
|
+
data = np.array(data)
|
|
155
185
|
self._series.append(
|
|
156
186
|
TGUniformSeries(
|
|
157
187
|
name=name,
|
|
@@ -163,6 +193,7 @@ class TimeseriesGraph(FigpackView):
|
|
|
163
193
|
width=width,
|
|
164
194
|
channel_spacing=channel_spacing,
|
|
165
195
|
auto_channel_spacing=auto_channel_spacing,
|
|
196
|
+
timestamps_for_inserting_nans=timestamps_for_inserting_nans,
|
|
166
197
|
)
|
|
167
198
|
)
|
|
168
199
|
|
|
@@ -320,6 +351,7 @@ class TGUniformSeries:
|
|
|
320
351
|
width: float = 1.0,
|
|
321
352
|
channel_spacing: Optional[float] = None,
|
|
322
353
|
auto_channel_spacing: Optional[float] = None,
|
|
354
|
+
timestamps_for_inserting_nans: Optional[np.ndarray] = None,
|
|
323
355
|
):
|
|
324
356
|
assert sampling_frequency_hz > 0, "Sampling frequency must be positive"
|
|
325
357
|
|
|
@@ -340,16 +372,27 @@ class TGUniformSeries:
|
|
|
340
372
|
self.sampling_frequency_hz = sampling_frequency_hz
|
|
341
373
|
self.data = data.astype(np.float32) # Ensure float32 for efficiency
|
|
342
374
|
|
|
375
|
+
if timestamps_for_inserting_nans is not None:
|
|
376
|
+
self.data = insert_nans_based_on_timestamps(
|
|
377
|
+
self.data,
|
|
378
|
+
start_time_sec=start_time_sec,
|
|
379
|
+
sampling_frequency_hz=sampling_frequency_hz,
|
|
380
|
+
timestamps=timestamps_for_inserting_nans,
|
|
381
|
+
)
|
|
382
|
+
|
|
343
383
|
if auto_channel_spacing is not None:
|
|
344
384
|
if channel_spacing is not None:
|
|
345
385
|
raise ValueError(
|
|
346
386
|
"Specify either channel_spacing or auto_channel_spacing, not both."
|
|
347
387
|
)
|
|
348
388
|
# Estimate RMS noise level across all channels using median absolute deviation
|
|
349
|
-
|
|
389
|
+
# Use nanmedian to handle NaN values properly
|
|
390
|
+
mad = np.nanmedian(
|
|
391
|
+
np.abs(self.data - np.nanmedian(self.data, axis=0)), axis=0
|
|
392
|
+
)
|
|
350
393
|
rms_estimate = mad / 0.6745 # Convert MAD to RMS estimate
|
|
351
|
-
channel_spacing = auto_channel_spacing * np.
|
|
352
|
-
if channel_spacing <= 0:
|
|
394
|
+
channel_spacing = auto_channel_spacing * np.nanmedian(rms_estimate)
|
|
395
|
+
if channel_spacing <= 0 or np.isnan(channel_spacing):
|
|
353
396
|
channel_spacing = 1.0 # Fallback to default spacing if estimate fails
|
|
354
397
|
self.channel_spacing = channel_spacing
|
|
355
398
|
|
|
@@ -559,3 +602,25 @@ class TGUniformSeries:
|
|
|
559
602
|
data=downsampled_array,
|
|
560
603
|
chunks=ds_chunks,
|
|
561
604
|
)
|
|
605
|
+
|
|
606
|
+
|
|
607
|
+
def insert_nans_based_on_timestamps(
|
|
608
|
+
x: np.ndarray,
|
|
609
|
+
*,
|
|
610
|
+
start_time_sec: float,
|
|
611
|
+
sampling_frequency_hz: float,
|
|
612
|
+
timestamps: np.ndarray,
|
|
613
|
+
):
|
|
614
|
+
end_timestamps = timestamps[-1]
|
|
615
|
+
ret_length = int((end_timestamps - start_time_sec) * sampling_frequency_hz) + 1
|
|
616
|
+
|
|
617
|
+
# Handle both 1D and 2D (multi-channel) data
|
|
618
|
+
if x.ndim == 1:
|
|
619
|
+
ret = np.nan * np.ones((ret_length,), dtype=x.dtype)
|
|
620
|
+
else: # x.ndim == 2
|
|
621
|
+
n_channels = x.shape[1]
|
|
622
|
+
ret = np.nan * np.ones((ret_length, n_channels), dtype=x.dtype)
|
|
623
|
+
|
|
624
|
+
indices = ((timestamps - start_time_sec) * sampling_frequency_hz).astype(int)
|
|
625
|
+
ret[indices] = x
|
|
626
|
+
return ret
|
figpack/views/__init__.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
figpack/__init__.py,sha256=
|
|
1
|
+
figpack/__init__.py,sha256=LjMDRaV7Q9-qfLZKQTqavTTOpyTnU5ca7ub_mtUYqPg,358
|
|
2
2
|
figpack/cli.py,sha256=s1mGQuFSntxiIvU6OWwHVlM9Cj-l1zMQ3OzFFe1-5ZE,11089
|
|
3
3
|
figpack/extensions.py,sha256=mILB4_F1RHkca4I7t88zh74IX8VCmfT7XFZZT4XYdNw,13009
|
|
4
4
|
figpack/core/__init__.py,sha256=7zU6O1piTk07aeCfbU81QqTgSHIO2n5MZ4LFNmsrtfs,192
|
|
@@ -12,19 +12,20 @@ figpack/core/_view_figure.py,sha256=GYTgSCWBxi1pR16aBgAYRcEuFcgj0vjsrLIVfy1HYzM,
|
|
|
12
12
|
figpack/core/config.py,sha256=oOR7SlP192vuFhYlS-h14HnG-kd_3gaz0vshXch2RNc,173
|
|
13
13
|
figpack/core/extension_view.py,sha256=FSBXdhFEWicLi0jhkuRdS-a8CNsULrEqqIKtYfV3tmI,1255
|
|
14
14
|
figpack/core/figpack_extension.py,sha256=KSJKlnLYueFnGa8QFMpbIF3CDMwnIZJOqsI0smz6cUc,2252
|
|
15
|
-
figpack/core/figpack_view.py,sha256=
|
|
15
|
+
figpack/core/figpack_view.py,sha256=gfL4v7qsM8B-mk16usOjHsX8mQ9CtYpRTYmXvgUxt10,7041
|
|
16
16
|
figpack/core/zarr.py,sha256=LTWOIX6vuH25STYTQS9_apfnfYXmATAEQkil3z9eYKE,1634
|
|
17
|
-
figpack/figpack-figure-dist/index.html,sha256=
|
|
18
|
-
figpack/figpack-figure-dist/assets/index-
|
|
17
|
+
figpack/figpack-figure-dist/index.html,sha256=Ck9GAOiENLh-pK-u6nzYjioAyvkPFQGlEHeusyLgucM,688
|
|
18
|
+
figpack/figpack-figure-dist/assets/index-CSkROe6e.js,sha256=EPasEr-CWjRh6Lchs9biEWuHJ7qMCBeVeEkypW-1KMk,2261859
|
|
19
19
|
figpack/figpack-figure-dist/assets/index-V5m_wCvw.css,sha256=WRtQLW6SNlTlLtepSOt89t1z41SD7XzYUyRldqowjMM,7286
|
|
20
20
|
figpack/figpack-figure-dist/assets/neurosift-logo-CLsuwLMO.png,sha256=g5m-TwrGh5f6-9rXtWV-znH4B0nHgc__0GWclRDLUHs,9307
|
|
21
21
|
figpack/views/Box.py,sha256=oN_OJH2pK_hH26k0eFCFjlfuJssVqKvw20GxYK1HX7g,2419
|
|
22
22
|
figpack/views/DataFrame.py,sha256=VGspmfWtnZ4Gvea5zd-ODpiJPQEp8gVv-ScDhVVCeyA,3400
|
|
23
23
|
figpack/views/Gallery.py,sha256=15ukt9CmgkbT8q_okEYYDESW1E7vOJkVPombSlrEWKw,3324
|
|
24
24
|
figpack/views/GalleryItem.py,sha256=b_upJno5P3ANSulbG-h3t6Xj56tPGJ7iVxqyiZu3zaQ,1244
|
|
25
|
+
figpack/views/Iframe.py,sha256=oPKRl_PT5Ko1JAYxW4ZmKLHXzTKGqbT1e9i9C1OXg7k,1063
|
|
25
26
|
figpack/views/Image.py,sha256=Nc8XNKQBm79iN6omZIsYEU6daNa_X3_IIbmt4q1Zb8k,3741
|
|
26
27
|
figpack/views/LayoutItem.py,sha256=wy8DggkIzZpU0F1zFIBceS7HpBb6lu-A3hpYINQzedk,1595
|
|
27
|
-
figpack/views/Markdown.py,sha256=
|
|
28
|
+
figpack/views/Markdown.py,sha256=U_6oJMD14WVhmX0WBa0h1RwEovI-n-lQXykJbBDxa5Q,1314
|
|
28
29
|
figpack/views/MatplotlibFigure.py,sha256=697xTOkNxcwYZrLoYOzh4CuME4NDUpIYzX-ckLE5aWU,2422
|
|
29
30
|
figpack/views/MountainLayout.py,sha256=JGvrhzqLR2im5d-m0TsZNy06KOR5iGfDlinrRqHpQsQ,2680
|
|
30
31
|
figpack/views/MountainLayoutItem.py,sha256=arYO1pD9RpXfHQKxtFagl66bjqSzEdafIf8ldDEMTD0,1451
|
|
@@ -33,15 +34,15 @@ figpack/views/Spectrogram.py,sha256=jcm26ucHedKDnBA5xnAUu9tW-g-ZutT-kw1EIhYm66E,
|
|
|
33
34
|
figpack/views/Splitter.py,sha256=BR2L-8aqicTubS1rSzsQ3XnhoJcX5GcfEnVWtEWEs0w,2016
|
|
34
35
|
figpack/views/TabLayout.py,sha256=AqdHPLcP2-caWjxbkC8r8m60z8n_eyZrIBGOOPSVNCs,1908
|
|
35
36
|
figpack/views/TabLayoutItem.py,sha256=xmHA0JsW_6naJze4_mQuP_Fy0Nm17p2N7w_AsmVRp8k,880
|
|
36
|
-
figpack/views/TimeseriesGraph.py,sha256=
|
|
37
|
-
figpack/views/__init__.py,sha256=
|
|
37
|
+
figpack/views/TimeseriesGraph.py,sha256=KdeB5XGsk_l1kzikuNvCPyvYwLFDuPvuaEuyaoqEl0g,21693
|
|
38
|
+
figpack/views/__init__.py,sha256=L4Ikj6s5VXZtKEATVFkY_szB14w6-nqh_vdP_FvD4kc,668
|
|
38
39
|
figpack/views/PlotlyExtension/PlotlyExtension.py,sha256=LOFSqbm46UZ7HsHTDxUPnNB33ydYQvEkRVK-TSKkzK4,2149
|
|
39
40
|
figpack/views/PlotlyExtension/__init__.py,sha256=80Wy1mDMWyagjuR99ECxJePIYpRQ6TSyHkB0uZoBZ_0,70
|
|
40
41
|
figpack/views/PlotlyExtension/_plotly_extension.py,sha256=yZjG1NMGlQedeeLdV6TQWpi_NTm5Wfk5eWbXEdZbbFE,1455
|
|
41
42
|
figpack/views/PlotlyExtension/plotly_view.js,sha256=9BjgOPkqGl87SSonnb48nFeQV3UTIi1trpSPxd9qlKo,3055
|
|
42
|
-
figpack-0.2.
|
|
43
|
-
figpack-0.2.
|
|
44
|
-
figpack-0.2.
|
|
45
|
-
figpack-0.2.
|
|
46
|
-
figpack-0.2.
|
|
47
|
-
figpack-0.2.
|
|
43
|
+
figpack-0.2.29.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
44
|
+
figpack-0.2.29.dist-info/METADATA,sha256=JJlSNDBnRwEQhzxeZmI3OSqSYoy86MX5WFDvPTlONK4,4618
|
|
45
|
+
figpack-0.2.29.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
46
|
+
figpack-0.2.29.dist-info/entry_points.txt,sha256=l6d3siH2LxXa8qJGbjAqpIZtI5AkMSyDeoRDCzdrUto,45
|
|
47
|
+
figpack-0.2.29.dist-info/top_level.txt,sha256=lMKGaC5xWmAYBx9Ac1iMokm42KFnJFjmkP2ldyvOo-c,8
|
|
48
|
+
figpack-0.2.29.dist-info/RECORD,,
|