diff --git a/docs/install.md b/docs/install.md index 3babf1f9..7b1dd52d 100644 --- a/docs/install.md +++ b/docs/install.md @@ -12,7 +12,7 @@ ## Installation Options -MagellanMapper can be installed depending on one's Python preferences. +MagellanMapper supports several Python setups. ### Install using Conda @@ -41,27 +41,28 @@ Install using Pip with Python >= 3.6 (see [Python versions](#python-version-supp pip install magellanmapper[most] --extra-index-url https://pypi.fury.io/dd8/ ``` -The `most` group installs the GUI and file import tools. The extra index accesses a few [customized dependencies](#custom-packages) for MagellanMapper. +The `most` group installs the GUI and file import tools (see [optional dependencies below](#optional-installation-groups)). The extra index accesses a few [customized dependencies](#custom-packages) for MagellanMapper. Java will need to be installed to support more image formats (eg from [here](https://www.azul.com/downloads/?package=jdk)). ### Developer installs -If you download the source code, you can install in developer mode for the latest updates and any changes you make. +You can install directly from the source code for the latest updates. -Download the repo: +First, download the repo: ```shell git clone https://github.com/sanderslab/magellanmapper.git ``` -For Conda: +Next, install it: +- For Conda: ```shell conda env create -n mag -f environment.yml ``` -Or Pip: +- Or Pip: ```shell pip install -e .[most] --extra-index-url https://pypi.fury.io/dd8/ @@ -152,7 +153,7 @@ On Windows, the [Microsoft Visual C++ Redistributable for Visual Studio 2015, 20 If installed from a Python package, enter your virtual environment and run: ```shell -pip install -U magellanmapper --extra-index-url https://pypi.fury.io/dd8/ +pip install -U magellanmapper --extra-index-url https://pypi.fury.io/dd8/ ``` If installed from source: @@ -167,27 +168,15 @@ Sometimes a virtual environment update is required for new depdendencies. ## Dependencies -The main required and optional dependencies in MagellanMapper are: - -- Scipy, Numpy, Matplotlib stack -- Mayavi/TraitsUI/Qt stack for GUI and 3D visualization -- Scikit-image for image processing -- Scikit-learn for machine learning based stats -- Pandas for stats -- [SimpleElastix](https://github.com/SuperElastix/SimpleElastix), a fork of SimpleITK with Elastix integrated (see below) -- Python-Bioformats/Javabridge for importing images from propriety formast such as `.czi` (optional, requires Java SDK and C compiler) - ### Python version support | MagellanMapper Version | Python Versions Supported | Deprecations | |-----|-----|-----| | < 1.4 | 3.6 | None | | 1.4-1.5 | 3.6-3.9 (no GUI support in 3.9) | None | -| 1.6a1-a2 | 3.6-3.9 (GUI support added for 3.9; MM 1.6a2 base group no longer installs GUI) | 3.6-3.7 to be removed in MM 1.7 | +| 1.6a1-a3 | 3.6-3.9 (GUI support added for 3.9; MM 1.6a2 base group no longer installs GUI) | 3.6-3.7 to be removed in MM 1.7 | | 1.6b1 | 3.6-3.11 (no GUI support in 3.10-3.11 as of 2022-12-30) | Same | -The `bin/setup_multi_venvs.sh`, `bin/build_deps.sh`, and their `.bat` counterparts are provided to build these dependencies for multiple Python versions. - As of MM 1.6a2, the GUI can be excluded by installing the base group, eg without `[gui]` or `[most]`. ### Pinned packages @@ -199,6 +188,21 @@ We've provided a few sets of pinned dependency versions: These package versions are used for automated testing (continuous integration). +### Optional installation groups + +| Group | Packages | Collection | +|-----|-----|-----| +| `most` | Import and GUI tools | Has `import`, `gui` | +| `all` | All groups plus `seaborn`, `scikit-learn` | Has all below | +| `import` | Imports proprietary image formats | | +| `gui` | Main graphical interface | | +| `pandas_plus` | Exports styled and Excel formats | | +| `aws` | Tools for accessing AWS | | +| `docs` | Tools for building docs | | +| `jupyter` | Running Notebooks | | +| `classifer` | Tensorflow | | +| `3D` | 3D rendering | | + ### Optional Dependency Build and Runtime Requirements #### Custom packages @@ -418,6 +422,12 @@ Additional errors: - An error with VTK has prevented display of 3D images at least as of VTK 8.1.2 on RHEL 7.5, though the same VTK version works on Ubuntu 18.04 +```Building TVTK classes... Windows fatal exception: code 0xc0000374``` or ```Building TVTK classes... Fatal Python error: Segmentation fault``` + +* Appears to be a sporadic installation issue (see [issue](https://github.com/sanderslab/magellanmapper/issues/401)) +* Workaround: reinstall Mayavi: `pip install mayavi` +* Starting with MM v1.6a4, Mayavi will no longer be installed by defaul + ### Display issues #### Window is too large for screen diff --git a/docs/release/release_v1.6.md b/docs/release/release_v1.6.md index ea045673..5bc75ad6 100644 --- a/docs/release/release_v1.6.md +++ b/docs/release/release_v1.6.md @@ -6,6 +6,7 @@ - Smoother, faster interactions with main plots, including atlas label name display, label editing, and pan and zoom navigation - Available as binary wheel to install without requiring the source code +- Faster, lighter installation with fewer required dependency packages - Simpler entry point to launch MagellanMapper: `mm` - Atlases can be downloaded directly through [`BrainGlobe`](https://github.com/brainglobe/bg-atlasapi) (see the new "Atlases" panel) - Atlas regions can be searched (see "Atlases > Region") @@ -177,7 +178,8 @@ - Updated to use the `axis_channel` parameter in Scikit-image's `transform.rescale` function (#115) - Seaborn as an optional dependency for additional plot support (currently only swarm plots, #137) - Scikit-learn is an optional rather than a required dependency (#150) -- The AWS-related dependencies (`boto3`, `awscli`) are now optional (#150, #379) +- The AWS-related dependencies (`boto3`, `awscli`) are now optional, installed in the `aws` group (#150, #379) +- Mayavi/VTK are now optional, installed in the `3d` group (#455) - The `jupyter` install group installs packages for running the Jupyter sample commands notebook in a Bash kernel (#122) - Missing dependencies are starting to use more consistent error messages and instructions (#226) - Python 3.6 and 3.7 have been deprecated for removal in MM v1.7 and have separate pinned dependencies (`envs/requirements_py3`) (#232, #379) diff --git a/envs/requirements.txt b/envs/requirements.txt index 8f0c5131..ec79b652 100644 --- a/envs/requirements.txt +++ b/envs/requirements.txt @@ -1,56 +1,53 @@ --extra-index-url https://pypi.fury.io/dd8/ appdirs==1.4.4 -apptools==5.2.0 bg-atlasapi @ https://github.com/brainglobe/bg-atlasapi/archive/dbecd16b2f63a8e167543f3358452a756bad0e64.tar.gz bg-space==0.6.0 certifi==2022.12.7 -charset-normalizer==2.1.1 +charset-normalizer==3.0.1 click==8.1.3 -commonmark==0.9.1 -configobj==5.0.6 -contourpy==1.0.6 +contourpy==1.0.7 cycler==0.11.0 -envisage==6.1.0 fonttools==4.38.0 future==0.18.3 idna==3.4 -imagecodecs==2022.12.24 -imageio==2.23.0 -importlib-resources==5.10.2 +imagecodecs==2023.1.23 +imageio==2.26.0 +importlib-resources==5.12.0 javabridge==1.0.19.post9+gc8c12b4 kiwisolver==1.4.4 -matplotlib==3.6.2 +lazy_loader==0.1 +markdown-it-py==2.2.0 +matplotlib==3.7.0 matplotlib-scalebar==0.8.1 -mayavi==4.8.1 +mdurl==0.1.2 meshio==5.3.4 -networkx==2.8.8 +networkx==3.0 numpy==1.24.2 -packaging==22.0 +packaging==23.0 pandas==1.5.3 Pillow==9.4.0 pyamg==4.2.3 pyface==7.4.4 Pygments==2.14.0 pyparsing==3.0.9 -PyQt5==5.15.7 +PyQt5==5.15.9 PyQt5-Qt5==5.15.2 -PyQt5-sip==12.11.0 +PyQt5-sip==12.11.1 python-bioformats==4.0.7.post5+g52309d1 python-dateutil==2.8.2 -pytz==2022.7 +pytz==2022.7.1 PyWavelets==1.4.1 PyYAML==6.0 -requests==2.28.1 -rich==13.0.0 -scikit-image==0.19.3 -scipy==1.10.0 +requests==2.28.2 +rich==13.3.1 +scikit-image==0.20.0 +scipy==1.9.1 SimpleITK==2.3.0.dev117+g0640d six==1.16.0 -tifffile==2022.10.10 +tifffile==2023.2.28 traits==6.4.1 -traitsui==7.4.2 +traitsui==7.4.3 treelib==1.6.1 -typing_extensions==4.4.0 -urllib3==1.26.13 -vtk==9.2.4 -zipp==3.11.0 +typing_extensions==4.5.0 +urllib3==1.26.14 +zipp==3.15.0 diff --git a/envs/requirements_py36 b/envs/requirements_py36 index 6460dcfd..31e5706e 100644 --- a/envs/requirements_py36 +++ b/envs/requirements_py36 @@ -1,28 +1,19 @@ --extra-index-url https://pypi.fury.io/dd8/ -aiohttp==3.8.1 -aiosignal==1.2.0 appdirs==1.4.4 -apptools==5.1.0 -async-timeout==4.0.2 -asynctest==0.13.0 -attrs==21.4.0 bg-atlasapi @ https://github.com/brainglobe/bg-atlasapi/archive/dbecd16b2f63a8e167543f3358452a756bad0e64.tar.gz bg-space==0.6.0 boto3==1.23.10 botocore==1.26.10 -certifi==2022.6.15 +certifi==2022.12.7 charset-normalizer==2.0.12 click==8.0.4 commonmark==0.9.1 -configobj==5.0.6 cycler==0.11.0 -dataclasses==0.8;python_version<"3.7" +dataclasses==0.8 decorator==4.4.2 -envisage==6.0.1 -frozenlist==1.2.0 -future==0.18.2 -idna==3.3 -idna-ssl==1.1.0 +future==0.18.3 +idna==3.4 +imagecodecs==2020.5.30 imageio==2.15.0 importlib-metadata==4.8.3 importlib-resources==5.4.0 @@ -31,40 +22,34 @@ jmespath==0.10.0 kiwisolver==1.3.1 matplotlib==3.3.4 matplotlib-scalebar==0.7.2 -mayavi==4.8.0 meshio==4.4.6 -multidict==5.2.0 networkx==2.5.1 numpy==1.19.5 pandas==1.1.5 Pillow==8.4.0 pyamg==4.2.3 -pyface==7.4.2 -Pygments==2.12.0 +pyface==7.4.4 +Pygments==2.14.0 pyparsing==3.0.9 PyQt5==5.15.6 PyQt5-Qt5==5.15.2 PyQt5-sip==12.9.1 python-bioformats==4.0.5.post2+g51eb88a python-dateutil==2.8.2 -pytz==2022.1 +pytz==2022.7.1 PyWavelets==1.1.1 PyYAML==6.0 requests==2.27.1 -rich==12.5.1 +rich==12.6.0 s3transfer==0.5.2 -scikit-image==0.17.2;python_version<"3.9" -scikit-image==0.19.3;python_version>="3.9" +scikit-image==0.17.2 scipy==1.5.4 SimpleITK==2.0.2rc2.dev785+g8ac4f six==1.16.0 tifffile==2020.9.3 -traits==6.3.2 -traitsui==7.4.0 +traits==6.4.1 +traitsui==7.4.3 treelib==1.6.1 typing_extensions==4.1.1 -urllib3==1.26.11 -vtk==9.1.0 -wslink==1.6.6 -yarl==1.7.2 +urllib3==1.26.14 zipp==3.6.0 diff --git a/envs/requirements_py37 b/envs/requirements_py37 index c6b969f5..6b0eb765 100644 --- a/envs/requirements_py37 +++ b/envs/requirements_py37 @@ -1,57 +1,47 @@ --extra-index-url https://pypi.fury.io/dd8/ -aiohttp==3.8.3 -aiosignal==1.2.0 appdirs==1.4.4 -apptools==5.2.0 -async-timeout==4.0.2 -asynctest==0.13.0 -attrs==22.1.0 bg-atlasapi @ https://github.com/brainglobe/bg-atlasapi/archive/dbecd16b2f63a8e167543f3358452a756bad0e64.tar.gz bg-space==0.6.0 -boto3==1.24.93 -botocore==1.27.93 -certifi==2022.9.24 -charset-normalizer==2.1.1 +boto3==1.26.83 +botocore==1.29.83 +certifi==2022.12.7 +charset-normalizer==3.0.1 click==8.1.3 -commonmark==0.9.1 -configobj==5.0.6 cycler==0.11.0 -envisage==6.1.0 -fonttools==4.37.4 -frozenlist==1.3.1 -future==0.18.2 +fonttools==4.38.0 +future==0.18.3 idna==3.4 imagecodecs==2021.11.20 -imageio==2.22.2 -importlib-metadata==5.0.0 -importlib-resources==5.10.0 +imageio==2.26.0 +importlib-metadata==6.0.0 +importlib-resources==5.12.0 javabridge==1.0.19.post4+gbebed64 jmespath==1.0.1 kiwisolver==1.4.4 +markdown-it-py==2.2.0 matplotlib==3.5.3 matplotlib-scalebar==0.8.1 -mayavi==4.8.1 +mdurl==0.1.2 meshio==5.3.4 -multidict==6.0.2 networkx==2.6.3 numpy==1.21.6 -packaging==21.3 +packaging==23.0 pandas==1.3.5 -Pillow==9.2.0 +Pillow==9.4.0 pyamg==4.2.3 -pyface==7.4.2 -Pygments==2.13.0 +pyface==7.4.4 +Pygments==2.14.0 pyparsing==3.0.9 -PyQt5==5.15.7 +PyQt5==5.15.9 PyQt5-Qt5==5.15.2 -PyQt5-sip==12.11.0 +PyQt5-sip==12.11.1 python-bioformats==4.0.5.post2+g51eb88a python-dateutil==2.8.2 -pytz==2022.5 +pytz==2022.7.1 PyWavelets==1.3.0 PyYAML==6.0 -requests==2.28.1 -rich==12.6.0 +requests==2.28.2 +rich==13.3.1 s3transfer==0.6.0 scikit-image==0.19.3 scipy==1.7.3 @@ -59,11 +49,8 @@ SimpleITK==2.0.2rc2.dev785+g8ac4f six==1.16.0 tifffile==2021.11.2 traits==6.4.1 -traitsui==7.4.1 +traitsui==7.4.3 treelib==1.6.1 -typing_extensions==4.4.0 -urllib3==1.26.12 -vtk==9.2.2 -wslink==1.8.4 -yarl==1.8.1 -zipp==3.9.0 +typing_extensions==4.5.0 +urllib3==1.26.14 +zipp==3.15.0 diff --git a/magmap/gui/visualizer.py b/magmap/gui/visualizer.py index de55cd39..e6c635f2 100644 --- a/magmap/gui/visualizer.py +++ b/magmap/gui/visualizer.py @@ -47,16 +47,24 @@ Int, List, observe, on_trait_change, Property, push_exception_handler, \ Str, HasTraits from traitsui.api import ArrayEditor, BooleanEditor, CheckListEditor, \ - EnumEditor, HGroup, HSplit, Item, ProgressEditor, RangeEditor, \ + EnumEditor, HGroup, HSplit, Item, NullEditor, ProgressEditor, RangeEditor, \ StatusItem, TextEditor, VGroup, View, Tabbed, TabularEditor from traitsui.basic_editor_factory import BasicEditorFactory from traitsui.qt4.editor import Editor from traitsui.tabular_adapter import TabularAdapter -from tvtk.pyface.scene_editor import SceneEditor -from tvtk.pyface.scene_model import SceneModelError -from mayavi.tools.mlab_scene_model import MlabSceneModel -from mayavi.core.ui.mayavi_scene import MayaviScene -import vtk + +try: + from tvtk.pyface.scene_editor import SceneEditor + from tvtk.pyface.scene_model import SceneModelError + from mayavi.tools.mlab_scene_model import MlabSceneModel + from mayavi.core.ui.mayavi_scene import MayaviScene + import vtk +except ImportError: + SceneEditor = None + SceneModelError = None + MlabSceneModel = None + MayaviScene = None + vtk = None from magmap.atlas import ontology from magmap.brain_globe import bg_controller @@ -85,9 +93,10 @@ def main(): # show complete stacktraces for debugging push_exception_handler(reraise_exceptions=True) - # suppress output window on Windows but print errors to console - vtk_out = vtk.vtkOutputWindow() - vtk_out.SetInstance(vtk_out) + if vtk is not None: + # suppress output window on Windows but print errors to console + vtk_out = vtk.vtkOutputWindow() + vtk_out.SetInstance(vtk_out) # create Trait-enabled GUI visualization = Visualization() @@ -496,7 +505,7 @@ class Visualization(HasTraits): flipz = True # True to invert 3D vis along z-axis controls_created = Bool(False) mpl_fig_active = Any - scene = Instance(MlabSceneModel, ()) + scene = None if MlabSceneModel is None else Instance(MlabSceneModel, ()) scene_3d_shown = False # 3D Mayavi display shown selected_viewer_tab = vis_handler.ViewerTabs.ROI_ED select_controls_tab = Int(-1) @@ -965,6 +974,9 @@ class Visualization(HasTraits): ) # tabbed panel with ROI Editor, Atlas Editor, and Mayavi scene + # (if installed) + mayavi_ed = NullEditor if SceneEditor is None else SceneEditor( + scene_class=MayaviScene) panel_figs = Tabbed( # set a small width to allow window to be resized down to this size Item("_roi_ed_fig", label="ROI Editor", show_label=False, @@ -972,14 +984,14 @@ class Visualization(HasTraits): Item("_atlas_ed_fig", label="Atlas Editor", show_label=False, editor=MPLFigureEditor()), Item("scene", label="3D Viewer", show_label=False, - editor=SceneEditor(scene_class=MayaviScene)), + editor=mayavi_ed), ) # icon as a Pyface resource if image file exists icon_img = (ImageResource(str(config.ICON_PATH)) if config.ICON_PATH.exists() else None) - # set up the GUI layout; + # set up the GUI layout view = View( # control the HSplit width ratio by setting min widths for an item in # each Tabbed view and initial window total width; panel_figs expands @@ -1698,25 +1710,28 @@ def _update_structure_level( if self._atlas_label is not None and self.scene_3d_shown: title = ontology.get_label_name(self._atlas_label) - if title is not None: + if title is not None and self.scene is not None: # update title in 3D viewer self._mlab_title = self.scene.mlab.title(title) - def _post_3d_display(self, title="clrbrain3d", show_orientation=True): + def _post_3d_display( + self, title: str = "magmap3d", show_orientation: bool = True): """Show axes and saved ROI parameters after 3D display. Args: - title: Path without extension to save file if - :attr:``config.savefig`` is set to an extension. Defaults to - "clrbrain3d". + title: Path without extension to save file if + :attr:``config.savefig`` is set to an extension. Defaults to + "magmap3d". show_orientation: True to show orientation axes; defaults to True. """ + if self.scene is None: return + if self.scene_3d_shown: if config.savefig in config.FORMATS_3D: path = "{}.{}".format(title, config.savefig) libmag.backup_file(path) try: - # save before setting any other objects to avoid VTK + # save before setting any other objects to avoid VTK # render error print("saving 3D scene to {}".format(path)) self.scene.mlab.savefig(path) @@ -1724,10 +1739,10 @@ def _post_3d_display(self, title="clrbrain3d", show_orientation=True): # the scene may not have been activated yet print("unable to save 3D surface") if show_orientation: - # TODO: cannot save file manually once orientation axes are on - # and have not found a way to turn them off easily, so - # consider turning them off by default and deferring to the - # GUI to turn them back on + # TODO: cannot save file manually once orientation axes are on + # and have not found a way to turn them off easily, so + # consider turning them off by default and deferring to the + # GUI to turn them back on self.show_orientation_axes(self.flipz) # updates the GUI here even though it doesn't elsewhere for some reason if self._rois_selections.selections: @@ -1793,6 +1808,11 @@ def show_3d(self): print("Main image has not been loaded, cannot show 3D Viewer") return + if self.scene is None: + self.update_status_bar_msg( + config.format_import_err("mayavi", task="3D viewing")) + return + # show raw 3D image unless selected not to curr_offset, curr_roi_size, feedback = self._check_roi_position() if Vis3dOptions.CLEAR.value in self._check_list_3d: @@ -1836,6 +1856,8 @@ def show_label_3d(self, label_id): Args: label_id: ID of label to display. """ + if self.scene is None: return + # get bounding box for label region bbox = cv_nd.get_label_bbox(config.labels_img, label_id) if bbox is None: return @@ -2450,6 +2472,8 @@ def orient_camera(self): """Provide a default camera orientation with orientation axes. """ + if self.scene is None: return + view = self.scene.mlab.view(*self.scene.mlab.view()[:3], "auto") roll = self.scene.mlab.roll(-175) if self.scene_3d_shown: @@ -2458,14 +2482,19 @@ def orient_camera(self): #self.scene.mlab.axes() # need to adjust units to microns print("Scene activated with view:", view, "roll:", roll) - def show_orientation_axes(self, flipud=False): - """Show orientation axes with option to flip z-axis to match - handedness in Matplotlib images with z increasing upward. + def show_orientation_axes(self, flipud: bool = False): + """Show orientation axes with option to flip z-axis. + + Allows adjusting z-axis to match handedness in Matplotlib images with + z increasing upward. Args: - flipud: True to invert z-axis, which also turns off arrowheads; + flipud: True to invert z-axis, which also turns off arrowheads; defaults to True. + """ + if self.scene is None: return + orient = self.scene.mlab.orientation_axes() if flipud: # flip z-axis and turn off now upside-down arrowheads @@ -2474,7 +2503,9 @@ def show_orientation_axes(self, flipud=False): @on_trait_change("scene.busy") def _scene_changed(self): - # show camera position after roll changes; only use roll for + if self.scene is None: return + + # show camera position after roll changes; only use roll for # simplification since almost any movement involves a roll change roll = self.scene.mlab.roll() if self._camera_pos is None or self._camera_pos["roll"] != roll: @@ -2724,7 +2755,8 @@ def get_atlas_cmap(coords): def show_3d_blobs(self): """Show blobs as spheres in 3D viewer.""" - if self.segments is None or len(self.segments) < 1: + if self.scene is None or self.segments is None or len( + self.segments) < 1: return # get blobs in ROI and display as spheres in Mayavi viewer @@ -2920,8 +2952,10 @@ def _launch_roi_editor(self): } if self._styles_2d[0] == Styles2D.SQUARE_3D.value: # layout for square ROIs with 3D screenshot for square-ish fig - screenshot = self.scene.mlab.screenshot( - mode="rgba", antialiased=True) if self.scene_3d_shown else None + screenshot = None + if self.scene_3d_shown and self.screen: + screenshot = self.scene.mlab.screenshot( + mode="rgba", antialiased=True) roi_ed.plot_2d_stack( *stack_args, **stack_args_named, mlab_screenshot=screenshot) elif self._styles_2d[0] == Styles2D.SINGLE_ROW.value: @@ -3218,7 +3252,7 @@ def _save_fig(self): self.atlas_eds[0].save_fig(path) elif self.selected_viewer_tab is vis_handler.ViewerTabs.MAYAVI: - if config.filename: + if self.scene is not None and config.filename: # save 3D image with extension in config screenshot = self.scene.mlab.screenshot( mode="rgba", antialiased=True) diff --git a/magmap/settings/config.py b/magmap/settings/config.py index 61a8ad13..21d83506 100644 --- a/magmap/settings/config.py +++ b/magmap/settings/config.py @@ -937,7 +937,7 @@ def format_import_err( if name is None: name = dist_name.capitalize() - task = "" if task is None else f"for {task}" - msg = f"{name} is required {task} but not installed. Please install, " \ + task = "" if task is None else f"for {task} " + msg = f"{name} is required {task}but not installed. Please install, " \ f"eg with 'pip install {dist_name}'." return msg diff --git a/setup.py b/setup.py index 7b6cf261..e7cbd9f0 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,5 @@ # MagellanMapper setup script -# Author: David Young, 2017, 2020 +# Author: David Young, 2017, 2023 import setuptools @@ -37,17 +37,18 @@ # optional dependencies for classification _EXTRAS_CLASSIFER = ["tensorflow"] -# optional dependencies for full GUI; note that this group is not necessary +# optional dependencies for main GUI; note that this group is not necessary # for the Matplotlib-based viewers (eg ROI Editor, Atlas Editor) _EXTRAS_GUI = [ # backend error with 5.15.8 - "PyQt5 <= 5.15.7", - "vtk", - "mayavi", + "PyQt5 != 5.15.8", "pyface", "traitsui", ] +#: Optional dependencies for the 3D viewer. +_EXTRAS_3D = ["mayavi"] + # installation configuration config = { "name": "magellanmapper", @@ -98,6 +99,7 @@ "jupyter": _EXTRAS_JUPYTER, "classifier": _EXTRAS_CLASSIFER, "gui": _EXTRAS_GUI, + "3d": _EXTRAS_3D, # dependencies for most common tasks "most": [ @@ -118,6 +120,7 @@ *_EXTRAS_IMPORT, *_EXTRAS_AWS, *_EXTRAS_JUPYTER, + *_EXTRAS_3D, ] }, }