Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drag-n-drop folder with mixed layer types (e.g. image.tiff and Points.csv) or just csv fails #5460

Open
Tracked by #5911
zcassi88 opened this issue Jan 9, 2023 · 17 comments 路 May be fixed by #6890
Open
Tracked by #5911

Drag-n-drop folder with mixed layer types (e.g. image.tiff and Points.csv) or just csv fails #5460

zcassi88 opened this issue Jan 9, 2023 · 17 comments 路 May be fixed by #6890
Labels
bug Something isn't working priority-high High priority issue UI/UX

Comments

@zcassi88
Copy link

zcassi88 commented Jan 9, 2023

馃悰 Bug

To Reproduce

Steps to reproduce the behavior:

  1. Open napari
  2. Open folder via menu or drag and drop
303 raise err_type(err_msg)
    err_type = <class 'ValueError'>
    err_msg = 'Could not find a backend to open `_path_`` with iomode `ri`.'

ValueError: Could not find a backend to open _path_`` with iomode ri`. -->

Expected behavior

Environment

  • Please copy and paste the information at napari info option in help menubar here:
    napari: 0.4.16
    Platform: Windows-10-10.0.19043-SP0
    Python: 3.10.6 | packaged by conda-forge | (main, Oct 24 2022, 16:02:16) [MSC v.1916 64 bit (AMD64)]
    Qt: 5.15.2
    PyQt5: 5.15.7
    NumPy: 1.23.4
    SciPy: 1.9.3
    Dask: 2022.10.0
    VisPy: 0.10.0

OpenGL:

  • GL version: 4.6.0 NVIDIA 430.86
  • MAX_TEXTURE_SIZE: 32768

Screens:

  • screen 1: resolution 1368x912, scale 2.0

Plugins:

  • napari-svg: 0.1.6
  • scikit-image: 0.4.16
@zcassi88 zcassi88 added the bug Something isn't working label Jan 9, 2023
@psobolewskiPhD
Copy link
Member

Hi, could you tell us what kind of files were in the folder?
Can you open the files individually?

Also, could you provide the full traceback?
You can use three backticks (`) and then paste it.

@zcassi88
Copy link
Author

We can open files singularly, they are csvs.

File C:\ProgramData\Anaconda3\envs\napari\lib\site-packages\napari\_qt\qt_viewer.py:754, in QtViewer._qt_open(self=<napari._qt.qt_viewer.QtViewer object>, filenames=['W:/scratch/garber/falaanto/059_PVcre_insitu/059_...y3vGluT_cy5cre/MIP_059_02_1_Region-6_nTiles-090_1'], stack=False, plugin=None, layer_type=None, **kwargs={})
    753 try:
--> 754     self.viewer.open(
        self.viewer = Viewer(axes=Axes(visible=False, labels=True, colored=True, dashed=False, arrows=True), camera=Camera(center=(0.0, 8800.150841520051, 9196.268823723072), zoom=0.11285815314530842, angles=(0.0, 0.0, 90.0), perspective=0.0, interactive=True), cursor=Cursor(position=(5601.445181189188, 5014.027625958364), scaled=True, size=1, style=<CursorStyle.STANDARD: 'standard'>), dims=Dims(ndim=2, ndisplay=2, last_used=0, range=((0.0, 2.0, 1.0), (0.0, 2.0, 1.0)), current_step=(0, 0), order=(0, 1), axis_labels=('0', '1')), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False), layers=[], scale_bar=ScaleBar(visible=False, colored=False, ticks=True, position=<Position.BOTTOM_RIGHT: 'bottom_right'>, font_size=10, unit=None), text_overlay=TextOverlay(visible=False, color=(0.5, 0.5, 0.5, 1.0), font_size=10, position=<TextOverlayPosition.TOP_LEFT: 'top_left'>, text=''), overlays=Overlays(interaction_box=InteractionBox(points=None, show=False, show_handle=False, show_vertices=False, selection_box_drag=None, selection_box_final=None, transform_start=<napari.utils.transforms.transforms.Affine object at 0x000001E1E6C6C490>, transform_drag=<napari.utils.transforms.transforms.Affine object at 0x000001E1E6C6C4F0>, transform_final=<napari.utils.transforms.transforms.Affine object at 0x000001E1E6C6C550>, transform=<napari.utils.transforms.transforms.Affine object at 0x000001E1E6C6C5B0>, allow_new_selection=True, selected_vertex=None)), help='', status='cre_vGlut2 [5601 5014]', tooltip=Tooltip(visible=False, text=''), theme='dark', title='napari', mouse_move_callbacks=[<function InteractionBoxMouseBindings.initialize_mouse_events.<locals>.mouse_move at 0x000001E1F42EB910>], mouse_drag_callbacks=[<function InteractionBoxMouseBindings.initialize_mouse_events.<locals>.mouse_drag at 0x000001E1F42E93F0>], mouse_double_click_callbacks=[], mouse_wheel_callbacks=[<function dims_scroll at 0x000001E1E6722710>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, keymap={'Shift': <function InteractionBoxMouseBindings.initialize_key_events.<locals>.hold_to_lock_aspect_ratio at 0x000001E1F42EA320>, 'Control-Shift-R': <function InteractionBoxMouseBindings._reset_active_layer_affine at 0x000001E1F4336830>, 'Control-Shift-A': <function InteractionBoxMouseBindings._transform_active_layer at 0x000001E1F43370A0>})
        self = <napari._qt.qt_viewer.QtViewer object at 0x000001E1E6C5A4D0>
        filenames = ['W:/scratch/garber/falaanto/059_PVcre_insitu/059_02/1_405Dapi_fluVgat_cy3vGluT_cy5cre/MIP_059_02_1_Region-6_nTiles-090_1']
        stack = False
        plugin = None
        layer_type = None
        kwargs = {}
    755         filenames,
    756         stack=stack,
    757         plugin=plugin,
    758         layer_type=layer_type,
    759         **kwargs,
    760     )
    761 except ReaderPluginError as e:

File C:\ProgramData\Anaconda3\envs\napari\lib\site-packages\napari\components\viewer_model.py:941, in ViewerModel.open(self=Viewer(axes=Axes(visible=False, labels=True, col...._transform_active_layer at 0x000001E1F43370A0>}), path=['W:/scratch/garber/falaanto/059_PVcre_insitu/059_...y3vGluT_cy5cre/MIP_059_02_1_Region-6_nTiles-090_1'], stack=False, plugin=None, layer_type=None, **kwargs={})
    939 # no plugin choice was made
    940 else:
--> 941     layers = self._open_or_raise_error(
        layers = <module 'napari.layers' from 'C:\\ProgramData\\Anaconda3\\envs\\napari\\lib\\site-packages\\napari\\layers\\__init__.py'>
        self = Viewer(axes=Axes(visible=False, labels=True, colored=True, dashed=False, arrows=True), camera=Camera(center=(0.0, 8800.150841520051, 9196.268823723072), zoom=0.11285815314530842, angles=(0.0, 0.0, 90.0), perspective=0.0, interactive=True), cursor=Cursor(position=(5601.445181189188, 5014.027625958364), scaled=True, size=1, style=<CursorStyle.STANDARD: 'standard'>), dims=Dims(ndim=2, ndisplay=2, last_used=0, range=((0.0, 2.0, 1.0), (0.0, 2.0, 1.0)), current_step=(0, 0), order=(0, 1), axis_labels=('0', '1')), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False), layers=[], scale_bar=ScaleBar(visible=False, colored=False, ticks=True, position=<Position.BOTTOM_RIGHT: 'bottom_right'>, font_size=10, unit=None), text_overlay=TextOverlay(visible=False, color=(0.5, 0.5, 0.5, 1.0), font_size=10, position=<TextOverlayPosition.TOP_LEFT: 'top_left'>, text=''), overlays=Overlays(interaction_box=InteractionBox(points=None, show=False, show_handle=False, show_vertices=False, selection_box_drag=None, selection_box_final=None, transform_start=<napari.utils.transforms.transforms.Affine object at 0x000001E1E6C6C490>, transform_drag=<napari.utils.transforms.transforms.Affine object at 0x000001E1E6C6C4F0>, transform_final=<napari.utils.transforms.transforms.Affine object at 0x000001E1E6C6C550>, transform=<napari.utils.transforms.transforms.Affine object at 0x000001E1E6C6C5B0>, allow_new_selection=True, selected_vertex=None)), help='', status='cre_vGlut2 [5601 5014]', tooltip=Tooltip(visible=False, text=''), theme='dark', title='napari', mouse_move_callbacks=[<function InteractionBoxMouseBindings.initialize_mouse_events.<locals>.mouse_move at 0x000001E1F42EB910>], mouse_drag_callbacks=[<function InteractionBoxMouseBindings.initialize_mouse_events.<locals>.mouse_drag at 0x000001E1F42E93F0>], mouse_double_click_callbacks=[], mouse_wheel_callbacks=[<function dims_scroll at 0x000001E1E6722710>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, keymap={'Shift': <function InteractionBoxMouseBindings.initialize_key_events.<locals>.hold_to_lock_aspect_ratio at 0x000001E1F42EA320>, 'Control-Shift-R': <function InteractionBoxMouseBindings._reset_active_layer_affine at 0x000001E1F4336830>, 'Control-Shift-A': <function InteractionBoxMouseBindings._transform_active_layer at 0x000001E1F43370A0>})
        stack = False
        _path = 'W:/scratch/garber/falaanto/059_PVcre_insitu/059_02/1_405Dapi_fluVgat_cy3vGluT_cy5cre/MIP_059_02_1_Region-6_nTiles-090_1'
        kwargs = {}
        layer_type = None
        [_path] = ['W:/scratch/garber/falaanto/059_PVcre_insitu/059_02/1_405Dapi_fluVgat_cy3vGluT_cy5cre/MIP_059_02_1_Region-6_nTiles-090_1']
    942         [_path], kwargs, layer_type, stack
    943     )
    944     added.extend(layers)

File C:\ProgramData\Anaconda3\envs\napari\lib\site-packages\napari\components\viewer_model.py:1064, in ViewerModel._open_or_raise_error(self=Viewer(axes=Axes(visible=False, labels=True, col...._transform_active_layer at 0x000001E1F43370A0>}), paths=['W:/scratch/garber/falaanto/059_PVcre_insitu/059_...y3vGluT_cy5cre/MIP_059_02_1_Region-6_nTiles-090_1'], kwargs={}, layer_type=None, stack=False)
   1062 # multiple plugins
   1063 else:
-> 1064     raise MultipleReaderError(
        trans = <napari.utils.translations.TranslationBundle object at 0x000001E1DF117C10>
        path_message = 'W:/scratch/garber/falaanto/059_PVcre_insitu/059_02/1_405Dapi_fluVgat_cy3vGluT_cy5cre/MIP_059_02_1_Region-6_nTiles-090_1'
        readers = {'napari': 'napari (npe2)', 'builtins': 'builtins (npe1)'}
        paths = ['W:/scratch/garber/falaanto/059_PVcre_insitu/059_02/1_405Dapi_fluVgat_cy3vGluT_cy5cre/MIP_059_02_1_Region-6_nTiles-090_1']
   1065         trans._(
   1066             "Multiple plugins found capable of reading {path_message}. Select plugin from {plugins} and pass to reading function e.g. `viewer.open(..., plugin=...)`.",
   1067             path_message=path_message,
   1068             plugins=readers,
   1069             deferred=True,
   1070         ),
   1071         list(readers.keys()),
   1072         paths,
   1073     )
   1075 return added

MultipleReaderError: Multiple plugins found capable of reading W:/scratch/garber/falaanto/059_PVcre_insitu/059_02/1_405Dapi_fluVgat_cy3vGluT_cy5cre/MIP_059_02_1_Region-6_nTiles-090_1. Select plugin from {'napari': 'napari (npe2)', 'builtins': 'builtins (npe1)'} and pass to reading function e.g. `viewer.open(..., plugin=...)`.

During handling of the above exception, another exception occurred:

ValueError                                Traceback (most recent call last)
File C:\ProgramData\Anaconda3\envs\napari\lib\site-packages\napari\_qt\qt_viewer.py:730, in QtViewer._open_folder_dialog(self=<napari._qt.qt_viewer.QtViewer object>)
    718 folder = dlg.getExistingDirectory(
    719     parent=self,
    720     caption=trans._('Select folder...'),
   (...)
    726     ),
    727 )
    729 if folder not in {'', None}:
--> 730     self._qt_open([folder], stack=False)
        folder = 'W:/scratch/garber/falaanto/059_PVcre_insitu/059_02/1_405Dapi_fluVgat_cy3vGluT_cy5cre/MIP_059_02_1_Region-6_nTiles-090_1'
        self = <napari._qt.qt_viewer.QtViewer object at 0x000001E1E6C5A4D0>
        [folder] = ['W:/scratch/garber/falaanto/059_PVcre_insitu/059_02/1_405Dapi_fluVgat_cy3vGluT_cy5cre/MIP_059_02_1_Region-6_nTiles-090_1']
    731     update_open_history(folder)

File C:\ProgramData\Anaconda3\envs\napari\lib\site-packages\napari\_qt\qt_viewer.py:772, in QtViewer._qt_open(self=<napari._qt.qt_viewer.QtViewer object>, filenames=['W:/scratch/garber/falaanto/059_PVcre_insitu/059_...y3vGluT_cy5cre/MIP_059_02_1_Region-6_nTiles-090_1'], stack=False, plugin=None, layer_type=None, **kwargs={})
    762     handle_gui_reading(
    763         filenames,
    764         self,
   (...)
    769         **kwargs,
    770     )
    771 except MultipleReaderError:
--> 772     handle_gui_reading(filenames, self, stack, **kwargs)
        filenames = ['W:/scratch/garber/falaanto/059_PVcre_insitu/059_02/1_405Dapi_fluVgat_cy3vGluT_cy5cre/MIP_059_02_1_Region-6_nTiles-090_1']
        stack = False
        kwargs = {}
        self = <napari._qt.qt_viewer.QtViewer object at 0x000001E1E6C5A4D0>

File C:\ProgramData\Anaconda3\envs\napari\lib\site-packages\napari\_qt\dialogs\qt_reader_dialog.py:156, in handle_gui_reading(paths=['W:/scratch/garber/falaanto/059_PVcre_insitu/059_...y3vGluT_cy5cre/MIP_059_02_1_Region-6_nTiles-090_1'], qt_viewer=<napari._qt.qt_viewer.QtViewer object>, stack=False, plugin_name=None, error=None, **kwargs={})
    154 display_name, persist = readerDialog.get_user_choices()
    155 if display_name:
--> 156     open_with_dialog_choices(
        display_name = 'builtins (npe1)'
        persist = False
        readerDialog = <napari._qt.dialogs.qt_reader_dialog.QtReaderDialog object at 0x000001E1F4DBB640>
        readerDialog._extension = ''
        readers = {'napari': 'napari (npe2)', 'builtins': 'builtins (npe1)'}
        paths = ['W:/scratch/garber/falaanto/059_PVcre_insitu/059_02/1_405Dapi_fluVgat_cy3vGluT_cy5cre/MIP_059_02_1_Region-6_nTiles-090_1']
        stack = False
        qt_viewer = <napari._qt.qt_viewer.QtViewer object at 0x000001E1E6C5A4D0>
        kwargs = {}
    157         display_name,
    158         persist,
    159         readerDialog._extension,
    160         readers,
    161         paths,
    162         stack,
    163         qt_viewer,
    164         **kwargs,
    165     )

File C:\ProgramData\Anaconda3\envs\napari\lib\site-packages\napari\_qt\dialogs\qt_reader_dialog.py:249, in open_with_dialog_choices(display_name='builtins (npe1)', persist=False, extension='', readers={'builtins': 'builtins (npe1)', 'napari': 'napari (npe2)'}, paths=['W:/scratch/garber/falaanto/059_PVcre_insitu/059_...y3vGluT_cy5cre/MIP_059_02_1_Region-6_nTiles-090_1'], stack=False, qt_viewer=<napari._qt.qt_viewer.QtViewer object>, **kwargs={})
    245 plugin_name = [
    246     p_name for p_name, d_name in readers.items() if d_name == display_name
    247 ][0]
    248 # may throw error, but we let it this time
--> 249 qt_viewer.viewer.open(paths, stack=stack, plugin=plugin_name, **kwargs)
        plugin_name = 'builtins'
        paths = ['W:/scratch/garber/falaanto/059_PVcre_insitu/059_02/1_405Dapi_fluVgat_cy3vGluT_cy5cre/MIP_059_02_1_Region-6_nTiles-090_1']
        qt_viewer.viewer = Viewer(axes=Axes(visible=False, labels=True, colored=True, dashed=False, arrows=True), camera=Camera(center=(0.0, 8800.150841520051, 9196.268823723072), zoom=0.11285815314530842, angles=(0.0, 0.0, 90.0), perspective=0.0, interactive=True), cursor=Cursor(position=(5601.445181189188, 5014.027625958364), scaled=True, size=1, style=<CursorStyle.STANDARD: 'standard'>), dims=Dims(ndim=2, ndisplay=2, last_used=0, range=((0.0, 2.0, 1.0), (0.0, 2.0, 1.0)), current_step=(0, 0), order=(0, 1), axis_labels=('0', '1')), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False), layers=[], scale_bar=ScaleBar(visible=False, colored=False, ticks=True, position=<Position.BOTTOM_RIGHT: 'bottom_right'>, font_size=10, unit=None), text_overlay=TextOverlay(visible=False, color=(0.5, 0.5, 0.5, 1.0), font_size=10, position=<TextOverlayPosition.TOP_LEFT: 'top_left'>, text=''), overlays=Overlays(interaction_box=InteractionBox(points=None, show=False, show_handle=False, show_vertices=False, selection_box_drag=None, selection_box_final=None, transform_start=<napari.utils.transforms.transforms.Affine object at 0x000001E1E6C6C490>, transform_drag=<napari.utils.transforms.transforms.Affine object at 0x000001E1E6C6C4F0>, transform_final=<napari.utils.transforms.transforms.Affine object at 0x000001E1E6C6C550>, transform=<napari.utils.transforms.transforms.Affine object at 0x000001E1E6C6C5B0>, allow_new_selection=True, selected_vertex=None)), help='', status='cre_vGlut2 [5601 5014]', tooltip=Tooltip(visible=False, text=''), theme='dark', title='napari', mouse_move_callbacks=[<function InteractionBoxMouseBindings.initialize_mouse_events.<locals>.mouse_move at 0x000001E1F42EB910>], mouse_drag_callbacks=[<function InteractionBoxMouseBindings.initialize_mouse_events.<locals>.mouse_drag at 0x000001E1F42E93F0>], mouse_double_click_callbacks=[], mouse_wheel_callbacks=[<function dims_scroll at 0x000001E1E6722710>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, keymap={'Shift': <function InteractionBoxMouseBindings.initialize_key_events.<locals>.hold_to_lock_aspect_ratio at 0x000001E1F42EA320>, 'Control-Shift-R': <function InteractionBoxMouseBindings._reset_active_layer_affine at 0x000001E1F4336830>, 'Control-Shift-A': <function InteractionBoxMouseBindings._transform_active_layer at 0x000001E1F43370A0>})
        stack = False
        kwargs = {}
        qt_viewer = <napari._qt.qt_viewer.QtViewer object at 0x000001E1E6C5A4D0>
    251 if persist:
    252     get_settings().plugins.extension2reader = {
    253         **get_settings().plugins.extension2reader,
    254         f'*{extension}': plugin_name,
    255     }

File C:\ProgramData\Anaconda3\envs\napari\lib\site-packages\napari\components\viewer_model.py:931, in ViewerModel.open(self=Viewer(axes=Axes(visible=False, labels=True, col...._transform_active_layer at 0x000001E1F43370A0>}), path=['W:/scratch/garber/falaanto/059_PVcre_insitu/059_...y3vGluT_cy5cre/MIP_059_02_1_Region-6_nTiles-090_1'], stack=False, plugin='builtins', layer_type=None, **kwargs={})
    928 for _path in pbr:
    929     if plugin:
    930         added.extend(
--> 931             self._add_layers_with_plugins(
        added = []
        self = Viewer(axes=Axes(visible=False, labels=True, colored=True, dashed=False, arrows=True), camera=Camera(center=(0.0, 8800.150841520051, 9196.268823723072), zoom=0.11285815314530842, angles=(0.0, 0.0, 90.0), perspective=0.0, interactive=True), cursor=Cursor(position=(5601.445181189188, 5014.027625958364), scaled=True, size=1, style=<CursorStyle.STANDARD: 'standard'>), dims=Dims(ndim=2, ndisplay=2, last_used=0, range=((0.0, 2.0, 1.0), (0.0, 2.0, 1.0)), current_step=(0, 0), order=(0, 1), axis_labels=('0', '1')), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False), layers=[], scale_bar=ScaleBar(visible=False, colored=False, ticks=True, position=<Position.BOTTOM_RIGHT: 'bottom_right'>, font_size=10, unit=None), text_overlay=TextOverlay(visible=False, color=(0.5, 0.5, 0.5, 1.0), font_size=10, position=<TextOverlayPosition.TOP_LEFT: 'top_left'>, text=''), overlays=Overlays(interaction_box=InteractionBox(points=None, show=False, show_handle=False, show_vertices=False, selection_box_drag=None, selection_box_final=None, transform_start=<napari.utils.transforms.transforms.Affine object at 0x000001E1E6C6C490>, transform_drag=<napari.utils.transforms.transforms.Affine object at 0x000001E1E6C6C4F0>, transform_final=<napari.utils.transforms.transforms.Affine object at 0x000001E1E6C6C550>, transform=<napari.utils.transforms.transforms.Affine object at 0x000001E1E6C6C5B0>, allow_new_selection=True, selected_vertex=None)), help='', status='cre_vGlut2 [5601 5014]', tooltip=Tooltip(visible=False, text=''), theme='dark', title='napari', mouse_move_callbacks=[<function InteractionBoxMouseBindings.initialize_mouse_events.<locals>.mouse_move at 0x000001E1F42EB910>], mouse_drag_callbacks=[<function InteractionBoxMouseBindings.initialize_mouse_events.<locals>.mouse_drag at 0x000001E1F42E93F0>], mouse_double_click_callbacks=[], mouse_wheel_callbacks=[<function dims_scroll at 0x000001E1E6722710>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, keymap={'Shift': <function InteractionBoxMouseBindings.initialize_key_events.<locals>.hold_to_lock_aspect_ratio at 0x000001E1F42EA320>, 'Control-Shift-R': <function InteractionBoxMouseBindings._reset_active_layer_affine at 0x000001E1F4336830>, 'Control-Shift-A': <function InteractionBoxMouseBindings._transform_active_layer at 0x000001E1F43370A0>})
        _path = 'W:/scratch/garber/falaanto/059_PVcre_insitu/059_02/1_405Dapi_fluVgat_cy3vGluT_cy5cre/MIP_059_02_1_Region-6_nTiles-090_1'
        [_path] = ['W:/scratch/garber/falaanto/059_PVcre_insitu/059_02/1_405Dapi_fluVgat_cy3vGluT_cy5cre/MIP_059_02_1_Region-6_nTiles-090_1']
        kwargs = {}
        plugin = 'builtins'
        layer_type = None
        stack = False
    932                 [_path],
    933                 kwargs=kwargs,
    934                 plugin=plugin,
    935                 layer_type=layer_type,
    936                 stack=stack,
    937             )
    938         )
    939     # no plugin choice was made
    940     else:
    941         layers = self._open_or_raise_error(
    942             [_path], kwargs, layer_type, stack
    943         )

File C:\ProgramData\Anaconda3\envs\napari\lib\site-packages\napari\components\viewer_model.py:1134, in ViewerModel._add_layers_with_plugins(self=Viewer(axes=Axes(visible=False, labels=True, col...._transform_active_layer at 0x000001E1F43370A0>}), paths=['W:/scratch/garber/falaanto/059_PVcre_insitu/059_...y3vGluT_cy5cre/MIP_059_02_1_Region-6_nTiles-090_1'], stack=False, kwargs={}, plugin='builtins', layer_type=None)
   1132 else:
   1133     assert len(paths) == 1
-> 1134     layer_data, hookimpl = read_data_with_plugins(
        paths = ['W:/scratch/garber/falaanto/059_PVcre_insitu/059_02/1_405Dapi_fluVgat_cy3vGluT_cy5cre/MIP_059_02_1_Region-6_nTiles-090_1']
        stack = False
        plugin = 'builtins'
   1135         paths, plugin=plugin, stack=stack
   1136     )
   1138 # glean layer names from filename. These will be used as *fallback*
   1139 # names, if the plugin does not return a name kwarg in their meta dict.
   1140 filenames = []

File C:\ProgramData\Anaconda3\envs\napari\lib\site-packages\napari\plugins\io.py:106, in read_data_with_plugins(paths=[r'W:\scratch\garber\falaanto\059_PVcre_insitu\059_...y3vGluT_cy5cre\MIP_059_02_1_Region-6_nTiles-090_1'], plugin='builtins', stack=False)
     96     raise ValueError(
     97         trans._(
     98             'Plugin {plugin!r} does not support file(s) {paths}',
   (...)
    102         )
    103     )
    105 hookimpl = hook_caller.get_plugin_implementation(plugin)
--> 106 layer_data = reader(npe1_path)
        npe1_path = 'W:\\scratch\\garber\\falaanto\\059_PVcre_insitu\\059_02\\1_405Dapi_fluVgat_cy3vGluT_cy5cre\\MIP_059_02_1_Region-6_nTiles-090_1'
        reader = <function magic_imread at 0x000001E1FACA1240>
    107 # if the reader returns a "null layer" sentinel indicating an empty
    108 # file, return an empty list, otherwise return the result or None
    109 if _is_null_layer_sentinel(layer_data):

File C:\ProgramData\Anaconda3\envs\napari\lib\site-packages\napari\types.py:144, in image_reader_to_layerdata_reader.<locals>.reader_function(*args=(r'W:\scratch\garber\falaanto\059_PVcre_insitu\059_...y3vGluT_cy5cre\MIP_059_02_1_Region-6_nTiles-090_1',), **kwargs={})
    142 @wraps(func)
    143 def reader_function(*args, **kwargs) -> List[LayerData]:
--> 144     result = func(*args, **kwargs)
        func = <function magic_imread at 0x000001E1E66FB640>
        args = ('W:\\scratch\\garber\\falaanto\\059_PVcre_insitu\\059_02\\1_405Dapi_fluVgat_cy3vGluT_cy5cre\\MIP_059_02_1_Region-6_nTiles-090_1',)
        kwargs = {}
    145     return [(result,)]

File C:\ProgramData\Anaconda3\envs\napari\lib\site-packages\napari\utils\io.py:257, in magic_imread(filenames=[r'W:\scratch\garber\falaanto\059_PVcre_insitu\059_...y3vGluT_cy5cre\MIP_059_02_1_Region-6_nTiles-090_1'], use_dask=True, stack=True)
    255 else:
    256     if shape is None:
--> 257         image = imread(filename)
        filename = 'W:\\scratch\\garber\\falaanto\\059_PVcre_insitu\\059_02\\1_405Dapi_fluVgat_cy3vGluT_cy5cre\\MIP_059_02_1_Region-6_nTiles-090_1\\PPN_L.csv'
    258         shape = image.shape
    259         dtype = image.dtype

File C:\ProgramData\Anaconda3\envs\napari\lib\site-packages\napari\utils\io.py:150, in imread(filename=r'W:\scratch\garber\falaanto\059_PVcre_insitu\059_...5cre\MIP_059_02_1_Region-6_nTiles-090_1\PPN_L.csv')
    148         return tifffile.imread(filename)
    149 else:
--> 150     return imageio.imread(filename)
        filename = 'W:\\scratch\\garber\\falaanto\\059_PVcre_insitu\\059_02\\1_405Dapi_fluVgat_cy3vGluT_cy5cre\\MIP_059_02_1_Region-6_nTiles-090_1\\PPN_L.csv'
        imageio = <module 'imageio.v2' from 'C:\\ProgramData\\Anaconda3\\envs\\napari\\lib\\site-packages\\imageio\\v2.py'>

File C:\ProgramData\Anaconda3\envs\napari\lib\site-packages\imageio\v2.py:226, in imread(uri=r'W:\scratch\garber\falaanto\059_PVcre_insitu\059_...5cre\MIP_059_02_1_Region-6_nTiles-090_1\PPN_L.csv', format=None, **kwargs={})
    223 imopen_args = decypher_format_arg(format)
    224 imopen_args["legacy_mode"] = True
--> 226 with imopen(uri, "ri", **imopen_args) as file:
        imopen_args = {'plugin': None, 'extension': None, 'legacy_mode': True}
        uri = 'W:\\scratch\\garber\\falaanto\\059_PVcre_insitu\\059_02\\1_405Dapi_fluVgat_cy3vGluT_cy5cre\\MIP_059_02_1_Region-6_nTiles-090_1\\PPN_L.csv'
    227     result = file.read(index=0, **kwargs)
    229 return result

File C:\ProgramData\Anaconda3\envs\napari\lib\site-packages\imageio\core\imopen.py:303, in imopen(uri=r'W:\scratch\garber\falaanto\059_PVcre_insitu\059_...5cre\MIP_059_02_1_Region-6_nTiles-090_1\PPN_L.csv', io_mode='ri', plugin=None, extension=None, format_hint=None, legacy_mode=True, **kwargs={})
    297         err_msg += (
    298             "\nBased on the extension, the following plugins might add capable backends:\n"
    299             f"{install_candidates}"
    300         )
    302 request.finish()
--> 303 raise err_type(err_msg)
        err_type = <class 'ValueError'>
        err_msg = 'Could not find a backend to open `W:\\scratch\\garber\\falaanto\\059_PVcre_insitu\\059_02\\1_405Dapi_fluVgat_cy3vGluT_cy5cre\\MIP_059_02_1_Region-6_nTiles-090_1\\PPN_L.csv`` with iomode `ri`.'

ValueError: Could not find a backend to open `W:\scratch\garber\falaanto\059_PVcre_insitu\059_02\1_405Dapi_fluVgat_cy3vGluT_cy5cre\MIP_059_02_1_Region-6_nTiles-090_1\PPN_L.csv`` with iomode `ri`.

@psobolewskiPhD
Copy link
Member

So just to be clear, if you manually open MIP_059_02_1_Region-6_nTiles-090_1\PPN_L.csv then the file works, but when it's in a folder and you try to import the whole folder, then you get the above traceback?

@psobolewskiPhD psobolewskiPhD changed the title ValueError: Could not find a backend to open ... ValueError: Could not find a backend to open ... when trying to Open folder Jan 11, 2023
@zcassi88
Copy link
Author

Exactly how you described it.

@psobolewskiPhD
Copy link
Member

psobolewskiPhD commented Apr 15, 2024

Ok! I have a reproducer when writing up #6846
Open astronaut, add a Points or Shapes layer.
User File > Save All Layers... and builtins Save to Folder
This works perfectly, you will get a TIFF and a .csv.
Each to the file will open properly individually.
Drag and drop the whole folder and you will get the error from the OP.
This is pretty sucky!
CC: @DragaDoncila

Edit: the workaround is to open the folder in your OS file browser and select the contents and drag and drop that. Then it will work! I would expect dragging and dropping a folder to work just the same. I guess the difference is that if you have a a folder of TIFF they get merged into a single layer stack. While if you drag and drop N TIFF files, you get N layers.
So there should be logic to load individually if the file types are not all the same IMO.

@psobolewskiPhD psobolewskiPhD added priority-high High priority issue UI/UX labels Apr 15, 2024
@psobolewskiPhD psobolewskiPhD changed the title ValueError: Could not find a backend to open ... when trying to Open folder Drag-n-drop folder with mixed layer types (e.g. image.tiff and Points.csv) or just csv fails Apr 15, 2024
@DragaDoncila
Copy link
Contributor

Yeah so there's a confluence of problems here unfortunately.

The first is that back in the day, we had a (mostly silent) convention that a list of paths was always to be stacked, and a single path wasn't. We started work on passing stack explicitly, but because of npe1, we haven't been able to fully push that down to the level of a manifest toggle for each reader contribution.

I guess the difference is that if you have a a folder of TIFF they get merged into a single layer stack.

So tbh I'm surprised to see this too, but this is a result specifically of the fact that our magic_imread is always called with the default value of stack=True.

While if you drag and drop N TIFF files, you get N layers.

You can hold Shift while dropping the selected files to force them to be stacked.

I'm not sure that we always want a different reader to be used for each file in a folder, if the user drags in a folder... Readers accept the folder paths directly, so it's up to them how they deal with what's inside. For our own builtin folder reader, I can imagine maybe wanting to special case this and potentially call a different reader for each file... but it's not immediately obvious to me that we want that.

@psobolewskiPhD
Copy link
Member

psobolewskiPhD commented Apr 17, 2024

Thanks for the insight.
I think the heuristic should be:

  • individual files -- do what we do now
  • folder:
    • does the folder contain all the same file type, that's not csv? Stack 'em by default, as we do now
    • any csv? load em individually

I strongly feel that by default the output of Save to folder (builtins) should be readable properly by napari (builtins).

@DragaDoncila
Copy link
Contributor

I strongly feel that by default the output of Save to folder (builtins) should be readable properly by napari (builtins).

I think that's a very valid feeling lol.

does the folder contain all the same file type, that's not csv? Stack 'em by default, as we do now any csv? load em individually

This feels maybe overly specific. What if we did all files same type- open with our usual reader and stack. Not all files same type? Open them file-by-file with our built in reader?

@psobolewskiPhD
Copy link
Member

psobolewskiPhD commented Apr 17, 2024

The specific case probably covers majority of use cases, but also I don't think stacking csv would work -- that's not how 3d shapes/points are "made"

Stacking would be only for image type extensions (maybe same shape, but that's in the eye of the beholder).

Edit: in workflows I've been helping with lately, the layer list is basically any number of image layers, plus few Points, a shapes, and optionally labels. So if there is csv in the folder it's a good tell that Save to folder was used. So to inverted that save operation and restore the layers, I'd want it all loaded as individual layers -- no stacking of anything.

Edit2: I'm also mentally merging behavior of Save all layers and Save all selected -- I think the logic could be identical for both?

@Czaki
Copy link
Collaborator

Czaki commented Apr 17, 2024

  • does the folder contain all the same file type, that's not csv? Stack 'em by default, as we do now

I think that we should stack only files that share prefix and has number suffix. So directory with

ch0_01.tif
ch0_02.tif
ch0_03.tif
ch1_01.tif
ch1_02.tif
ch1_03.tif

It should be read as two layers.

@psobolewskiPhD
Copy link
Member

I think that's another level of sophistication/magic...

@Czaki
Copy link
Collaborator

Czaki commented Apr 18, 2024

I think that's another level of sophistication/magic...

You need some magic to load layers in proper order.

@psobolewskiPhD
Copy link
Member

I think by default what should work is that a saved folder of layers is opened as a layer list.
Order is less important, but could be gleaned from the time stamps of the writing out of the files?

Folders not saved by napari all bets are off in terms of the order. How can we be able to guess?
Just load the layers and people can sort.

@DragaDoncila
Copy link
Contributor

Folders not saved by napari all bets are off in terms of the order.

Not sure if you mean this explicitly, but we can't currently distinguish whether napari originally saved the folder. We could absolutely change our built-in writer to do save a small piece of metadata to indicate this, but we don't currently do that.

Also just to clarify, what we're talking about here doesn't really change how we do reading at an architecture level, but rather changes the behaviour of the built-in napari reader right?

@psobolewskiPhD
Copy link
Member

Right. Reading arbitrary folders and guessing intent will be hard and never perfect.
But we should ensure we have logic to reading builtins exported folders as layers. Order being correct would be nice but is easy to fix after import.

Of course if we need to we can write a .file with export but I think that is overkill since dragging all the files after Select All does work correctly.

@DragaDoncila
Copy link
Contributor

@psobolewskiPhD I'd be happy to look at a PR with your desired behaviour implemented. Here is the code that lists the directory and makes a list of all the filenames, and here is the code that actually does the reading.

@psobolewskiPhD
Copy link
Member

Thanks @DragaDoncila
I'll take a look -- this actually came up during a workshop I ran today!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working priority-high High priority issue UI/UX
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants