Skip to content

Commit

Permalink
Merge pull request #300 from NeurodataWithoutBorders/local-file-browser
Browse files Browse the repository at this point in the history
Better local file component
  • Loading branch information
luiztauffer committed Jun 28, 2023
2 parents 38df708 + 4853f87 commit 7bfb2f4
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 64 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,8 @@
# Upcoming

### New features
* Improved browsing and reading local NWB files with Panel, using ipyfilechooser [PR #300](https://github.com/NeurodataWithoutBorders/nwbwidgets/pull/300)

### Fixes
* Fix I/O issues when streaming data on Panel [PR #295](https://github.com/NeurodataWithoutBorders/nwbwidgets/pull/295)
* Fix plotly Figure not showing up, pinned Plotly version [PR #297](https://github.com/NeurodataWithoutBorders/nwbwidgets/pull/297)
Expand Down
78 changes: 15 additions & 63 deletions nwbwidgets/panel.py
Expand Up @@ -6,6 +6,7 @@
import ipywidgets as widgets
from dandi.dandiapi import DandiAPIClient
from fsspec.implementations.cached import CachingFileSystem
from ipyfilechooser import FileChooser
from pynwb import NWBHDF5IO
from tqdm.notebook import tqdm

Expand Down Expand Up @@ -48,7 +49,6 @@ def __init__(

self.source_options_names = list()
if enable_local_source:
self.source_options_names.append("Local dir")
self.source_options_names.append("Local file")
if enable_dandi_source:
self.source_options_names.append("DANDI")
Expand Down Expand Up @@ -83,8 +83,8 @@ def __init__(
self.source_options_radio.observe(self.updated_source, "value")

if enable_local_source:
self.source_options_radio.value = "Local dir"
self.create_components_local_dir_source()
self.source_options_radio.value = "Local file"
self.create_components_local_file_source()
elif enable_dandi_source:
self.source_options_radio.value = "DANDI"
self.create_components_dandi_source()
Expand All @@ -95,8 +95,6 @@ def updated_source(self, args=None):
self.create_components_dandi_source()
elif args["new"] == "S3":
self.create_components_s3_source()
elif args["new"] == "Local dir":
self.create_components_local_dir_source()
elif args["new"] == "Local file":
self.create_components_local_file_source()

Expand Down Expand Up @@ -182,69 +180,28 @@ def create_components_s3_source(self):
self.source_s3_button.on_click(self.stream_s3_file)
self.cache_checkbox.observe(self.toggle_cache)

def create_components_local_dir_source(self):
"""Create widgets components for Loca dir option"""
self.local_dir_path = widgets.Text(
value="",
description="Dir path:",
layout=widgets.Layout(width="400px", overflow=None),
)
self.local_dir_button = widgets.Button(description="Search")
self.local_dir_top = widgets.HBox(
children=[self.local_dir_path, self.local_dir_button],
layout=widgets.Layout(padding="5px 0px 5px 0px"),
)
self.local_dir_files = widgets.Dropdown(
options=[],
description="Files:",
layout=widgets.Layout(width="400px", overflow=None),
)
self.local_dir_file_button = widgets.Button(icon="check", description="Load file")
self.local_dir_panel = widgets.VBox(
children=[
self.local_dir_top,
self.local_dir_files,
self.local_dir_file_button,
],
layout=widgets.Layout(padding="5px 0px 5px 0px"),
)
self.source_changing_panel.children = [self.local_dir_panel]
self.local_dir_button.on_click(self.list_local_dir_files)
self.local_dir_file_button.on_click(self.load_local_dir_file)

def create_components_local_file_source(self):
"""Create widgets components for Local file option"""
self.local_file_path = widgets.Text(
value="",
description="File path:",
layout=widgets.Layout(width="400px", overflow=None),
)
self.local_file_button = widgets.Button(icon="check", description="Load file")
self.local_file_chooser = FileChooser()
self.local_file_chooser.sandbox_path = str(Path.cwd())
self.local_file_chooser.filter_pattern = ["*.nwb"]
self.local_file_chooser.title = "<b>Select local NWB file</b>"
self.local_file_chooser.register_callback(self.load_local_file)
self.local_file_panel = widgets.VBox(
children=[self.local_file_path, self.local_file_button],
children=[self.local_file_chooser],
layout=widgets.Layout(padding="5px 0px 5px 0px"),
)
self.source_changing_panel.children = [self.local_file_panel]
self.local_file_button.on_click(self.load_local_file)

def list_dandiset_files_dropdown(self, args=None):
"""Populate dropdown with all files and text area with summary"""
self.dandi_summary.value = "Loading dandiset info..."
self.source_dandi_file_dropdown.options = []
dandiset_id = self.source_dandi_id.value.split("-")[0].strip()
self.source_dandi_file_dropdown.options = list_dandiset_files(dandiset_id=dandiset_id)

metadata = get_dandiset_metadata(dandiset_id=dandiset_id)
self.dandi_summary.value = "<style>p{word-wrap: break-word}</style> <p>" + metadata.description + "</p>"

def list_local_dir_files(self, args=None):
"""List NWB files in local dir"""
if Path(self.local_dir_path.value).is_dir():
all_files = [f.name for f in Path(self.local_dir_path.value).glob("*.nwb")]
self.local_dir_files.options = all_files
else:
print("Invalid local dir path")

def stream_dandiset_file(self, args=None):
"""Stream NWB file from DANDI"""
self.widgets_panel.children = [widgets.Label("loading...")]
Expand Down Expand Up @@ -290,19 +247,14 @@ def _stream_s3_file(self, s3_url):
self.nwbfile = self.io.read()
self.widgets_panel.children = [nwb2widget(self.nwbfile)]

def load_local_dir_file(self, args=None):
"""Load local NWB file"""
full_file_path = str(Path(self.local_dir_path.value) / self.local_dir_files.value)
io = NWBHDF5IO(full_file_path, mode="r", load_namespaces=True)
nwb = io.read()
self.widgets_panel.children = [nwb2widget(nwb)]

def load_local_file(self, args=None):
"""Load local NWB file"""
full_file_path = str(Path(self.local_file_path.value))
io = NWBHDF5IO(full_file_path, mode="r", load_namespaces=True)
nwb = io.read()
self.widgets_panel.children = [nwb2widget(nwb)]
full_file_path = str(Path(self.local_file_chooser.selected))
if self.io:
self.io.close()
self.io = NWBHDF5IO(full_file_path, mode="r", load_namespaces=True)
self.nwbfile = self.io.read()
self.widgets_panel.children = [nwb2widget(self.nwbfile)]

def process_dandiset(self, dandiset):
try:
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Expand Up @@ -20,3 +20,4 @@ fsspec
requests
aiohttp
ipydatawidgets==4.3.2
ipyfilechooser==0.6.0
1 change: 0 additions & 1 deletion test/test_file.py
Expand Up @@ -27,7 +27,6 @@ def test_panel():
assert isinstance(panel, widgets.Widget)

# Change dropdown options for coverage
panel.source_options_radio.value = "Local dir"
panel.source_options_radio.value = "Local file"
panel.source_options_radio.value = "S3"
panel.source_options_radio.value = "DANDI"
Expand Down

0 comments on commit 7bfb2f4

Please sign in to comment.