Skip to content

Commit 199970f

Browse files
committed
update zarr functionality
1 parent 3803c9b commit 199970f

File tree

3 files changed

+19
-7
lines changed

3 files changed

+19
-7
lines changed

paper/joss/paper.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ Neurodata Without Borders files are structured hierarchically and encapsulate va
4242

4343
# Architecture and technical innovation
4444

45-
Neurosift is a *static* React/TypeScript website, meaning that it is delivered to the user's browser exactly as stored, without the need for dynamic server-side processing of requests. This approach simplifies deployment and maintenance; it is currently hosted on GitHub Pages, but could easily be deployed to any other static hosting service.
45+
Neurosift is a *static* React/TypeScript website, meaning that it is delivered to the user's browser exactly as stored, without the need for dynamic server-side processing of requests. This approach simplifies deployment and maintenance; it can be deployed to any static hosting service.
4646

4747
The main technical challenge in developing Neurosift was the requirement to lazy-load data objects from remote NWB files, which are built on the complex HDF5 format. While HDF5's efficient data organization is ideal for the large, multidimensional datasets typical in neurophysiology, its primary implementations are in the C language. This necessitates a creative solution to enable efficient web-based access to these files. To bridge this gap, Neurosift leverages WebAssembly to run compiled C code in the browser, specifically utilizing a modified version of the h5wasm [@h5wasm] library. Unlike the unmodified h5wasm, which primarily handles fully downloaded files, Neurosift's fork introduces an innovative approach to efficiently read data chunks from remote files. This allows for synchronous data reads without the need for a prior download of the entire file. This solution not only makes Neurosift a powerful tool for neuroscience research but also showcases the potential of WebAssembly in overcoming challenges associated with web-based data analysis tools.
4848

python/neurosift/cli.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def view_nwb(file):
1818
abs_fname = os.path.abspath(file)
1919
base_fname = os.path.basename(abs_fname)
2020
with TemporaryDirectory(prefix="view_nwb") as tmpdir:
21-
# create a symbolic link to the file
21+
# create a symbolic link to the file (or zarr folder)
2222
os.symlink(abs_fname, f'{tmpdir}/{base_fname}')
2323

2424
# this directory
@@ -59,8 +59,14 @@ def view_nwb(file):
5959
# run the service
6060
process = subprocess.Popen(['npm', 'run', 'start', tmpdir], cwd=f'{this_directory}/local-file-access-js', shell=shell, env=dict(os.environ, PORT=str(port)))
6161

62+
zarr_param = ''
63+
if os.path.isdir(abs_fname):
64+
if not os.path.exists(f'{abs_fname}/.zmetadata'):
65+
raise Exception(f'{abs_fname} is a directory but does not contain a .zmetadata file.')
66+
zarr_param = '&zarr=1'
67+
6268
# open the browser
63-
url = f"https://flatironinstitute.github.io/neurosift/?p=/nwb&url=http://localhost:{port}/files/{base_fname}"
69+
url = f"https://flatironinstitute.github.io/neurosift/?p=/nwb&url=http://localhost:{port}/files/{base_fname}{zarr_param}"
6470
print(f'Opening {url}')
6571
webbrowser.open(url)
6672

python/neurosift/local-file-access-js/src/index.js

+10-4
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ if (!dir) {
66
console.error('Please specify a directory.')
77
process.exit(-1)
88
}
9+
console.info('Serving files in', dir)
910

1011
// Allow CORS from flatironinstitute.github.io and localhost:3000
11-
const allowedOrigins = ['https://flatironinstitute.github.io', 'http://localhost:3000']
12+
const allowedOrigins = ['https://flatironinstitute.github.io', 'http://localhost:3000', 'http://localhost:4200']
1213
app.use((req, resp, next) => {
1314
const origin = req.get('origin')
1415
const allowedOrigin = allowedOrigins.includes(origin) ? origin : undefined
@@ -26,19 +27,24 @@ app.options('*', (req, resp) => {
2627
// Serve files
2728
app.get('/files/:fileName(*)', async (req, resp) => {
2829
const fileName = req.params.fileName
29-
3030
// Check if the file is shareable
3131
if (!isShareable(fileName)) {
32+
console.warn('Access to this file is forbidden.', fileName)
3233
resp.send(500).send('Access to this file is forbidden.')
3334
return
3435
}
3536

3637
// Send the file
3738
const options = {
38-
root: dir
39+
root: dir,
40+
// let's allow dot files for now
41+
dotfiles: 'allow'
3942
}
4043
resp.sendFile(fileName, options, function (err) {
4144
// I think it's important to have an error handler even if it's just this. (not sure though)
45+
if (err) {
46+
console.warn('Error sending file:', err)
47+
}
4248
})
4349
})
4450

@@ -54,7 +60,7 @@ function isShareable(f) {
5460
}
5561
const fileName = bb[bb.length - 1]
5662
if (fileName.startsWith('.')) {
57-
if (!['.zattrs'].includes(fileName)) {
63+
if (!['.zattrs', '.zgroup', '.zarray', '.zmetadata'].includes(fileName)) {
5864
// don't show hidden files (with some exceptions)
5965
return false
6066
}

0 commit comments

Comments
 (0)