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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Standalone solara #10

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ body:
import ipygoldenlayout; print("ipygoldenlayout", ipygoldenlayout.__version__)
import ipypopout; print("ipypopout", ipypopout.__version__)
import jinja2; print("Jinja2", jinja2.__version__)
import voila; print("voila", voila.__version__)
import solara; print("solara", solara.__version__)
import vispy; print("vispy", vispy.__version__)
import sidecar; print("sidecar", sidecar.__version__)
import jdaviz; print("Jdaviz", jdaviz.__version__)
2 changes: 1 addition & 1 deletion conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def pytest_configure(config):
PYTEST_HEADER_MODULES['ipysplitpanes'] = 'ipysplitpanes'
PYTEST_HEADER_MODULES['ipygoldenlayout'] = 'ipygoldenlayout'
PYTEST_HEADER_MODULES['ipypopout'] = 'ipypopout'
PYTEST_HEADER_MODULES['voila'] = 'voila'
PYTEST_HEADER_MODULES['solara'] = 'solara'
PYTEST_HEADER_MODULES['vispy'] = 'vispy'
PYTEST_HEADER_MODULES['gwcs'] = 'gwcs'
PYTEST_HEADER_MODULES['asdf'] = 'asdf'
Expand Down
95 changes: 18 additions & 77 deletions jdaviz/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@
import inspect
import os
import pathlib
import sys
import tempfile

from voila.app import Voila
from voila.configuration import VoilaConfiguration

from jdaviz import __version__
from jdaviz.app import _verbosity_levels, ALL_JDAVIZ_CONFIGS
Expand Down Expand Up @@ -38,21 +33,14 @@ def main(filepaths=None, layout='default', instrument=None, browser='default',
browser : str, optional
Path to browser executable.
theme : {'light', 'dark'}
Theme to use for Voila app or Jupyter Lab.
Theme to use for application.
verbosity : {'debug', 'info', 'warning', 'error'}
Verbosity of the popup messages in the application.
history_verbosity : {'debug', 'info', 'warning', 'error'}
Verbosity of the history logger in the application.
hotreload : bool
Whether to enable hot-reloading of the UI (for development)
"""
import logging # Local import to avoid possibly messing with JWST pipeline logger.

# Tornado Webserver py3.8 compatibility hotfix for windows
if sys.platform == 'win32':
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

if filepaths:
# Convert paths to posix string; windows paths are not JSON compliant
file_list = [pathlib.Path(f).absolute().as_posix() for f in filepaths]
Expand All @@ -63,74 +51,27 @@ def main(filepaths=None, layout='default', instrument=None, browser='default',
else:
file_list = []

if layout == '':
if len(file_list) <= 1:
notebook = "jdaviz_cli_launcher.ipynb"
else:
raise ValueError("'layout' argument is required when specifying multiple files")
else:
notebook = "jdaviz_cli.ipynb"

with open(JDAVIZ_DIR / notebook) as f:
notebook_template = f.read()

start_dir = os.path.abspath('.')
if layout == '' and len(file_list) > 1:
raise ValueError("'layout' argument is required when specifying multiple files")

# Keep track of start directory in environment variable so that it can be
# easily accessed e.g. in the file load dialog.
os.environ['JDAVIZ_START_DIR'] = start_dir

nbdir = tempfile.mkdtemp()

os.environ['JDAVIZ_START_DIR'] = os.path.abspath('.')

from solara.__main__ import cli
from jdaviz import solara
solara.config = layout.capitalize()
solara.data_list = file_list
if layout == 'mosviz':
solara.load_data_kwargs = {'instrument': instrument}
solara.jdaviz_verbosity = verbosity
solara.jdaviz_history_verbosity = history_verbosity
args = []
if hotreload:
notebook_template = notebook_template.replace("# PREFIX", "from jdaviz import enable_hot_reloading; enable_hot_reloading()") # noqa: E501

with open(os.path.join(nbdir, 'notebook.ipynb'), 'w') as nbf:
nbf.write(
notebook_template
.replace('CONFIG', layout.capitalize())
.replace('DATA_LIST', str(file_list))
.replace('JDAVIZ_VERBOSITY', verbosity)
.replace('JDAVIZ_HISTORY_VERBOSITY', history_verbosity)
# Mosviz specific changes
.replace('load_data(data', 'load_data(directory=data' if layout == 'mosviz' else 'load_data(data') # noqa: E501
.replace(') #ADDITIONAL_LOAD_DATA_ARGS', f', instrument=\'{instrument}\')' if layout == 'mosviz' else ')') # noqa: E501
.strip()
)

os.chdir(nbdir)

try:
logging.getLogger('tornado.access').disabled = True
Voila.notebook_path = 'notebook.ipynb'
VoilaConfiguration.template = 'jdaviz-default'
VoilaConfiguration.enable_nbextensions = True
VoilaConfiguration.file_whitelist = ['.*']
VoilaConfiguration.theme = theme
if browser != 'default':
Voila.browser = browser

voila = Voila.instance()
# monkey patch listen, so we can get a handle on the kernel_manager
# after it is created
previous_listen = voila.listen

def listen(*args, **kwargs):
# monkey patch remove_kernel, so we can stop the event loop
# when a kernel is removed (which means the browser page was closed)
previous_remove_kernel = voila.kernel_manager.remove_kernel

def remove_kernel(kernel_id):
previous_remove_kernel(kernel_id)
voila.ioloop.stop()

voila.kernel_manager.remove_kernel = remove_kernel
return previous_listen(*args, **kwargs)

voila.listen = listen
sys.exit(voila.launch_instance(argv=[]))
finally:
os.chdir(start_dir)
args += ['--auto-restart']
else:
args += ['--production']
cli(['run', 'jdaviz.solara'] + args)


def _main(config=None):
Expand Down
2 changes: 1 addition & 1 deletion jdaviz/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ def pytest_configure(config):
PYTEST_HEADER_MODULES['ipysplitpanes'] = 'ipysplitpanes'
PYTEST_HEADER_MODULES['ipygoldenlayout'] = 'ipygoldenlayout'
PYTEST_HEADER_MODULES['ipypopout'] = 'ipypopout'
PYTEST_HEADER_MODULES['voila'] = 'voila'
PYTEST_HEADER_MODULES['solara'] = 'solara'
PYTEST_HEADER_MODULES['vispy'] = 'vispy'
PYTEST_HEADER_MODULES['gwcs'] = 'gwcs'
PYTEST_HEADER_MODULES['asdf'] = 'asdf'
Expand Down
26 changes: 16 additions & 10 deletions jdaviz/core/launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,16 @@ class Launcher(v.VuetifyTemplate):
mosviz_icon = Unicode(read_icon(os.path.join(ICON_DIR, 'mosviz_icon.svg'), 'svg+xml')).tag(sync=True) # noqa
imviz_icon = Unicode(read_icon(os.path.join(ICON_DIR, 'imviz_icon.svg'), 'svg+xml')).tag(sync=True) # noqa

def __init__(self, main, configs=ALL_JDAVIZ_CONFIGS, filepath='', height=None, *args, **kwargs):
def __init__(self, main=None, configs=ALL_JDAVIZ_CONFIGS, filepath='',
height=None, *args, **kwargs):
self.vdocs = 'latest' if 'dev' in __version__ else 'v'+__version__

if main is None:
main = v.Sheet(class_="mx-25",
attributes={"id": "popout-widget-container"},
color="#00212C",
height=height)

self.main = main
self.configs = configs
self.height = f"{height}px" if isinstance(height, int) else height
Expand Down Expand Up @@ -189,14 +196,19 @@ def vue_launch_config(self, event):
config = event.get('config')
helper = _launch_config_with_data(config, self.loaded_data,
filepath=self.filepath, show=False)
if self.height != '100%':
if self.height not in ['100%', '100vh']:
# We're in jupyter mode. Set to default height
default_height = helper.app.state.settings['context']['notebook']['max_height']
helper.app.layout.height = default_height
self.main.height = default_height
self.main.color = 'transparent'
self.main.children = [helper.app]

@property
def main_with_launcher(self):
self.main.children = [self]
return self.main


def show_launcher(configs=ALL_JDAVIZ_CONFIGS, filepath='', height='450px'):
'''Display an interactive Jdaviz launcher to select your data and compatible configuration
Expand All @@ -213,11 +225,5 @@ def show_launcher(configs=ALL_JDAVIZ_CONFIGS, filepath='', height='450px'):
'''
# Color defined manually due to the custom theme not being defined yet (in main_styles.vue)
height = f"{height}px" if isinstance(height, int) else height
main = v.Sheet(class_="mx-25",
attributes={"id": "popout-widget-container"},
color="#00212C",
height=height,
_metadata={'mount_id': 'content'})
main.children = [Launcher(main, configs, filepath, height)]

show_widget(main, loc='inline', title=None)
launcher = Launcher(None, configs, filepath, height)
show_widget(launcher.main_with_launcher, loc='inline', title=None)
40 changes: 0 additions & 40 deletions jdaviz/jdaviz_cli.ipynb

This file was deleted.

41 changes: 0 additions & 41 deletions jdaviz/jdaviz_cli_launcher.ipynb

This file was deleted.

10 changes: 10 additions & 0 deletions jdaviz/solara.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.solara-content-main {
padding-top: 0 !important;
}
.widget-output {
margin: 0;
}
.v-content.jdaviz__content--not-in-notebook {
height: 100vh;
max-height: 100vh;
}
49 changes: 49 additions & 0 deletions jdaviz/solara.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import os
from pathlib import Path

import solara
import ipygoldenlayout
import ipysplitpanes
import ipyvue

import jdaviz
from jdaviz.app import custom_components

config = None
data_list = []
load_data_kwargs = {}
jdaviz_verbosity = 'error'
jdaviz_history_verbosity = 'info'


@solara.component
def Page():
if config is None:
solara.Text("No config defined")
return

ipysplitpanes.SplitPanes()
ipygoldenlayout.GoldenLayout()
for name, path in custom_components.items():
ipyvue.register_component_from_file(None, name,
os.path.join(os.path.dirname(jdaviz.__file__), path))

ipyvue.register_component_from_file('g-viewer-tab', "container.vue", jdaviz.__file__)

solara.Style(Path(__file__).parent / "solara.css")

if not len(data_list):
from jdaviz.core.launcher import Launcher
launcher = Launcher(height='100vh', filepath=(data_list[0] if len(data_list) == 1 else ''))
solara.display(launcher.main_with_launcher)
return

viz = getattr(jdaviz.configs, config)(verbosity=jdaviz_verbosity,
history_verbosity=jdaviz_history_verbosity)
for data in data_list:
if config == 'mosviz':
viz.load_data(directory=data, **load_data_kwargs)
else:
viz.load_data(data, **load_data_kwargs)

solara.display(viz.app)
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ dependencies = [
"ipysplitpanes>=0.1.0",
"ipygoldenlayout>=0.3.0",
"ipywidgets>=8.0.6",
"voila>=0.4,<0.5",
"solara>=1.32",
"pyyaml>=5.4.1",
"specutils>=1.15",
"specreduce>=1.4.1",
Expand Down Expand Up @@ -105,6 +105,7 @@ jdaviz = [
"data/*",
"data/*/*",
"*.vue",
"*.css",
"components/*.vue",
"configs/*/*/*/*.vue",
"configs/*/*.yaml",
Expand Down
3 changes: 1 addition & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,7 @@ def user_dir():

class DevelopCmd(develop):
prefix_targets = [
(os.path.join("nbconvert", "templates"), 'jdaviz-default'),
(os.path.join("voila", "templates"), 'jdaviz-default')
(os.path.join("nbconvert", "templates"), 'jdaviz-default')
]

def run(self):
Expand Down
Loading