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.

@@ -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-DnHZdWys.js"></script>
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>
@@ -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)
@@ -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
- mad = np.median(np.abs(self.data - np.median(self.data, axis=0)), axis=0)
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.median(rms_estimate)
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
@@ -2,6 +2,7 @@ from .Box import Box
2
2
  from .DataFrame import DataFrame
3
3
  from .Gallery import Gallery
4
4
  from .GalleryItem import GalleryItem
5
+ from .Iframe import Iframe
5
6
  from .Image import Image
6
7
  from .LayoutItem import LayoutItem
7
8
  from .Markdown import Markdown
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: figpack
3
- Version: 0.2.27
3
+ Version: 0.2.29
4
4
  Summary: A Python package for creating shareable, interactive visualizations in the browser
5
5
  Author-email: Jeremy Magland <jmagland@flatironinstitute.org>
6
6
  License: Apache-2.0
@@ -1,4 +1,4 @@
1
- figpack/__init__.py,sha256=zxhqr0lde2J_mnAi73-7r4CZptcqrtGZIZB7Tj5AJos,358
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=rD94SehOcb_OVlZJuVK9UdH-dOJ-Mjlvg5cX1JEoH0w,6853
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=RA68WkQC-75AbzX32U3SGbbipP9NpkAMSXJWrfVCPkI,688
18
- figpack/figpack-figure-dist/assets/index-DnHZdWys.js,sha256=YxHgJeAv3feDI2INjrt9_7a86niyJ8eL7gqaRxU-Zs4,1108653
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=ojUmeVf7gEh4nUSnbyg62dKNpwgQOLFDYV84w2NS5EQ,1133
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=ygbgB83CIc5z_FN6gedWB_KIGh9Zo6LwrCafJqWckfU,19011
37
- figpack/views/__init__.py,sha256=V09R6vFRzhY7ANevWomM7muFfUieXZEjGimPiMHpey4,641
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.27.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
43
- figpack-0.2.27.dist-info/METADATA,sha256=1_RNdRpyaQQaJD0ZoqyWjWNAn2WcgrIdlfDLfFGYtes,4618
44
- figpack-0.2.27.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
45
- figpack-0.2.27.dist-info/entry_points.txt,sha256=l6d3siH2LxXa8qJGbjAqpIZtI5AkMSyDeoRDCzdrUto,45
46
- figpack-0.2.27.dist-info/top_level.txt,sha256=lMKGaC5xWmAYBx9Ac1iMokm42KFnJFjmkP2ldyvOo-c,8
47
- figpack-0.2.27.dist-info/RECORD,,
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,,