figpack 0.3.4__tar.gz → 0.3.6__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.
- {figpack-0.3.4/figpack.egg-info → figpack-0.3.6}/PKG-INFO +2 -2
- {figpack-0.3.4 → figpack-0.3.6}/README.md +1 -1
- {figpack-0.3.4 → figpack-0.3.6}/figpack/__init__.py +1 -1
- figpack-0.3.6/figpack/core/zarr.py +129 -0
- figpack-0.3.6/figpack/figpack-figure-dist/assets/index-BQ9mn8rh.css +1 -0
- figpack-0.3.4/figpack/figpack-figure-dist/assets/index-P3Ni9vtI.js → figpack-0.3.6/figpack/figpack-figure-dist/assets/index-VDagO1Xz.js +61 -61
- {figpack-0.3.4 → figpack-0.3.6}/figpack/figpack-figure-dist/index.html +2 -2
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/TimeseriesGraph.py +10 -0
- {figpack-0.3.4 → figpack-0.3.6/figpack.egg-info}/PKG-INFO +2 -2
- {figpack-0.3.4 → figpack-0.3.6}/figpack.egg-info/SOURCES.txt +2 -2
- {figpack-0.3.4 → figpack-0.3.6}/pyproject.toml +1 -1
- figpack-0.3.4/figpack/core/zarr.py +0 -61
- figpack-0.3.4/figpack/figpack-figure-dist/assets/index-V5m_wCvw.css +0 -1
- {figpack-0.3.4 → figpack-0.3.6}/LICENSE +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/MANIFEST.in +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/cli.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/core/__init__.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/core/_bundle_utils.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/core/_file_handler.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/core/_save_figure.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/core/_server_manager.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/core/_show_view.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/core/_upload_bundle.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/core/_view_figure.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/core/_zarr_consolidate.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/core/config.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/core/extension_view.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/core/figpack_extension.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/core/figpack_view.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/extensions.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/figpack-figure-dist/assets/neurosift-logo-CLsuwLMO.png +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/utils/__init__.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/Box.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/CaptionedView.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/DataFrame.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/Gallery.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/GalleryItem.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/Iframe.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/Image.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/LayoutItem.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/Markdown.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/MatplotlibFigure.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/MountainLayout.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/MountainLayoutItem.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/MultiChannelTimeseries.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/PlotlyExtension/PlotlyExtension.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/PlotlyExtension/__init__.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/PlotlyExtension/_plotly_extension.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/PlotlyExtension/plotly_view.js +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/Spectrogram.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/Splitter.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/TabLayout.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/TabLayoutItem.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack/views/__init__.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack-serve/worker/container/app.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack.egg-info/dependency_links.txt +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack.egg-info/entry_points.txt +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack.egg-info/requires.txt +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/figpack.egg-info/top_level.txt +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/setup.cfg +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/tests/test_box.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/tests/test_cli.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/tests/test_core.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/tests/test_dataframe.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/tests/test_extension_system.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/tests/test_figpack_view.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/tests/test_file_handler.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/tests/test_gallery.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/tests/test_image.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/tests/test_markdown.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/tests/test_matplotlib_figure.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/tests/test_multichannel_timeseries.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/tests/test_plotly_figure.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/tests/test_server_manager.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/tests/test_spectrogram.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/tests/test_splitter.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/tests/test_tablayout.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/tests/test_timeseries_graph.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/tests/test_upload_bundle.py +0 -0
- {figpack-0.3.4 → figpack-0.3.6}/tests/test_view_figure.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: figpack
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.6
|
|
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
|
|
@@ -133,7 +133,7 @@ If you use figpack in your research, please cite it:
|
|
|
133
133
|
|
|
134
134
|
Or in APA format:
|
|
135
135
|
|
|
136
|
-
> Magland, J. (2025). figpack (Version 0.3.
|
|
136
|
+
> Magland, J. (2025). figpack (Version 0.3.6) [Computer software]. Zenodo. https://doi.org/10.5281/zenodo.17419621
|
|
137
137
|
|
|
138
138
|
## Contributing
|
|
139
139
|
|
|
@@ -57,7 +57,7 @@ If you use figpack in your research, please cite it:
|
|
|
57
57
|
|
|
58
58
|
Or in APA format:
|
|
59
59
|
|
|
60
|
-
> Magland, J. (2025). figpack (Version 0.3.
|
|
60
|
+
> Magland, J. (2025). figpack (Version 0.3.6) [Computer software]. Zenodo. https://doi.org/10.5281/zenodo.17419621
|
|
61
61
|
|
|
62
62
|
## Contributing
|
|
63
63
|
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
from typing import Any, Dict
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
_UNSPECIFIED = object()
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Group:
|
|
9
|
+
def __init__(self, zarr_group):
|
|
10
|
+
self._zarr_group = zarr_group
|
|
11
|
+
|
|
12
|
+
def create_group(self, name: str) -> "Group":
|
|
13
|
+
return Group(self._zarr_group.create_group(name))
|
|
14
|
+
|
|
15
|
+
def create_dataset(
|
|
16
|
+
self,
|
|
17
|
+
name: str,
|
|
18
|
+
*,
|
|
19
|
+
data=_UNSPECIFIED,
|
|
20
|
+
dtype=_UNSPECIFIED,
|
|
21
|
+
chunks=_UNSPECIFIED,
|
|
22
|
+
compressor=_UNSPECIFIED,
|
|
23
|
+
) -> None:
|
|
24
|
+
kwargs = {}
|
|
25
|
+
if data is not _UNSPECIFIED:
|
|
26
|
+
kwargs["data"] = data
|
|
27
|
+
if dtype is not _UNSPECIFIED:
|
|
28
|
+
kwargs["dtype"] = dtype
|
|
29
|
+
if chunks is not _UNSPECIFIED:
|
|
30
|
+
kwargs["chunks"] = chunks
|
|
31
|
+
else:
|
|
32
|
+
if data is not _UNSPECIFIED:
|
|
33
|
+
chunks2 = _get_optimal_chunk_size(data.shape, data.dtype)
|
|
34
|
+
if chunks2 is not _UNSPECIFIED:
|
|
35
|
+
kwargs["chunks"] = chunks2
|
|
36
|
+
if compressor is not _UNSPECIFIED:
|
|
37
|
+
kwargs["compressor"] = compressor
|
|
38
|
+
if _check_zarr_version() == 2:
|
|
39
|
+
self._zarr_group.create_dataset(name, **kwargs)
|
|
40
|
+
elif _check_zarr_version() == 3:
|
|
41
|
+
self._zarr_group.create_array(name, **kwargs) # type: ignore
|
|
42
|
+
else:
|
|
43
|
+
raise RuntimeError("Unsupported Zarr version")
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def attrs(self) -> Dict[str, Any]:
|
|
47
|
+
return self._zarr_group.attrs # type: ignore
|
|
48
|
+
|
|
49
|
+
def __getitem__(self, key: str) -> Any:
|
|
50
|
+
return self._zarr_group[key]
|
|
51
|
+
|
|
52
|
+
# implement in operator
|
|
53
|
+
def __contains__(self, key: str) -> bool:
|
|
54
|
+
return key in self._zarr_group
|
|
55
|
+
|
|
56
|
+
def __iter__(self):
|
|
57
|
+
return iter(self._zarr_group)
|
|
58
|
+
|
|
59
|
+
def __reversed__(self):
|
|
60
|
+
return reversed(self._zarr_group)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _check_zarr_version():
|
|
64
|
+
import zarr
|
|
65
|
+
|
|
66
|
+
version = zarr.__version__
|
|
67
|
+
major_version = int(version.split(".")[0])
|
|
68
|
+
return major_version
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _get_optimal_chunk_size(shape: tuple, dtype) -> tuple:
|
|
72
|
+
"""Compute an optimal chunk shape targeting ~5 MB per chunk,
|
|
73
|
+
chunking along only one dimension and avoiding mostly empty chunks.
|
|
74
|
+
"""
|
|
75
|
+
target_bytes = 5 * 1024 * 1024 # 5 MB
|
|
76
|
+
|
|
77
|
+
if np.prod(shape) <= 1:
|
|
78
|
+
# all dimensions are zero or one
|
|
79
|
+
# return shape of unspecified to let zarr choose on this edge case
|
|
80
|
+
return _UNSPECIFIED
|
|
81
|
+
|
|
82
|
+
# Ensure dtype is a numpy dtype to get itemsize
|
|
83
|
+
if isinstance(dtype, str):
|
|
84
|
+
dtype = np.dtype(dtype)
|
|
85
|
+
|
|
86
|
+
itemsize = np.dtype(dtype).itemsize
|
|
87
|
+
|
|
88
|
+
# Total array size in bytes
|
|
89
|
+
total_bytes = np.prod(shape) * itemsize
|
|
90
|
+
if total_bytes <= target_bytes:
|
|
91
|
+
# Entire array fits comfortably in one chunk
|
|
92
|
+
return shape
|
|
93
|
+
|
|
94
|
+
# Choose the first non-singleton dimension to chunk along
|
|
95
|
+
for axis, dim in enumerate(shape):
|
|
96
|
+
if dim > 1:
|
|
97
|
+
break
|
|
98
|
+
else:
|
|
99
|
+
return shape # all singleton
|
|
100
|
+
|
|
101
|
+
# Compute how many elements fit in target_bytes
|
|
102
|
+
target_elements = target_bytes // itemsize
|
|
103
|
+
|
|
104
|
+
# Compute product of all other dimensions (fixed)
|
|
105
|
+
other_size = np.prod(shape) // shape[axis]
|
|
106
|
+
|
|
107
|
+
# Determine chunk length along chosen axis
|
|
108
|
+
chunk_len = max(1, min(shape[axis], target_elements // other_size))
|
|
109
|
+
|
|
110
|
+
# Construct chunk shape
|
|
111
|
+
chunk_shape = list(shape)
|
|
112
|
+
chunk_shape[axis] = chunk_len
|
|
113
|
+
|
|
114
|
+
return tuple([int(c) for c in chunk_shape])
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
if __name__ == "__main__":
|
|
118
|
+
# Test the _get_optimal_chunk_size function for a variety of shapes and dtypes
|
|
119
|
+
test_cases = [
|
|
120
|
+
((1000, 1000), np.float32),
|
|
121
|
+
((5000, 2000), np.uint8),
|
|
122
|
+
((100, 100, 100), np.float64),
|
|
123
|
+
((10, 30, 30, 1500), np.int16),
|
|
124
|
+
((1, 1, 1), np.float32),
|
|
125
|
+
]
|
|
126
|
+
|
|
127
|
+
for shape, dtype in test_cases:
|
|
128
|
+
chunk_size = _get_optimal_chunk_size(shape, dtype)
|
|
129
|
+
print(f"Optimal chunk size for shape {shape} and dtype {dtype}: {chunk_size}")
|
|
@@ -0,0 +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;color:#213547;background-color:#fff;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:#747bff}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:#f9f9f9;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;left:0;right:0;height:30px;background-color:#f5f5f5;color:#333;display:flex;align-items:center;padding:0 12px;font-size:12px;border-top:1px solid #ddd;z-index:1000}.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;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:#d0d0d0}.about-button{background-color:#e0e0e0;color:#333;border:1px solid #ccc;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:#d0d0d0}.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:#fff;color:#333;border-radius:8px;max-width:600px;max-height:80vh;width:90%;box-shadow:0 4px 20px #00000026;overflow:hidden}.about-dialog-header{display:flex;justify-content:space-between;align-items:center;padding:16px 20px;border-bottom:1px solid #ddd}.about-dialog-header h2{margin:0;font-size:18px;font-weight:600}.about-dialog-close{background:none;border:none;color:#333;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:#f0f0f0}.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:#f5f5f5;color:#333;padding:2px 4px;border-radius:3px;font-family:Courier New,monospace;font-size:.9em}.about-dialog-description pre{background-color:#f5f5f5;color:#333;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 #ccc;padding-left:16px;margin:12px 0;font-style:italic}.manage-edits-view{display:flex;align-items:center;margin-left:12px}.edits-notification{color:#e65100;font-weight:500;margin-right:8px}.save-changes-button{background-color:#ff9800;color:#fff;border:1px solid #f57c00;padding:4px 8px;border-radius:4px;cursor:pointer;font-size:11px;height:22px;transition:background-color .2s}.save-changes-button:hover{background-color:#f57c00}.dialog-overlay{position:fixed;inset:0;background-color:#00000080;display:flex;justify-content:center;align-items:center;z-index:2000}.dialog-content{background-color:#fff;color:#333;border-radius:8px;max-width:500px;width:90%;box-shadow:0 4px 20px #00000026;overflow:hidden}.dialog-header{display:flex;justify-content:space-between;align-items:center;padding:16px 20px;border-bottom:1px solid #ddd}.dialog-header h3{margin:0;font-size:18px;font-weight:600}.dialog-close{background:none;border:none;color:#333;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}.dialog-close:hover{background-color:#f0f0f0}.dialog-body{padding:20px}.dialog-body p{margin:0 0 12px;line-height:1.5}.dialog-footer{padding:16px 20px;border-top:1px solid #ddd;display:flex;justify-content:flex-end}.dialog-button{background-color:#e0e0e0;color:#333;border:1px solid #ccc;padding:8px 16px;border-radius:4px;cursor:pointer;font-size:14px;transition:background-color .2s}.dialog-button:hover{background-color:#d0d0d0}.dialog-fullscreen{position:fixed;inset:0;background-color:#fff;color:#333;z-index:2000;display:flex;flex-direction:column}.dialog-content-fullscreen{display:flex;flex-direction:column;height:100%;overflow:hidden}.dialog-content-fullscreen .dialog-header{flex-shrink:0}.dialog-content-fullscreen .dialog-body{flex:1;overflow-y:auto;padding:20px}.dialog-content-fullscreen .dialog-footer{flex-shrink:0}
|