class SettingsEditor(v.VuetifyTemplate): template_file = os.path.join(os.path.dirname(__file__), "vue/vjsf.vue") vjsf_loaded = traitlets.Bool(False).tag(sync=True) values = traitlets.Dict(default_value={}).tag(sync=True) schema = traitlets.Dict().tag(sync=True) valid = traitlets.Bool(False).tag(sync=True)
class Base(trt.HasTraits): """A common base class to standardize properties and interactions""" elements_by_id: ty.Dict[str, dict] = trt.Dict( key_trait=trt.Unicode(), value_trait=trt.Dict(), ) elements_by_type: ty.Dict[str, ty.Tuple[str]] = trt.Dict( key_trait=trt.Unicode(), value_trait=trt.Tuple(), ) relationship_types: ty.Tuple[str] = trt.Tuple() def update(self, elements: dict): """Subclasses must implement this!""" warnings.warn(f"{self.__class__.__name__} does not " f"specialize the `update` method!") def get_element_by_id(self, id_: str) -> dict: return self.elements_by_id[id_] def get_name_by_id(self, id_: str) -> str: return self.get_element_by_id(id_).get("name") @trt.observe("elements_by_id") def _update_elements(self, *_): self.update(elements=self.elements_by_id)
class PlotViewer(widgets.DOMWidget): """The time series visualization widget.""" _view_name = traitlets.Unicode('PlotView').tag(sync=True) _model_name = traitlets.Unicode('PlotModel').tag(sync=True) _view_module = traitlets.Unicode('tfma_widget_js').tag(sync=True) _model_module = traitlets.Unicode('tfma_widget_js').tag(sync=True) _view_module_version = traitlets.Unicode('^0.1.0').tag(sync=True) _model_module_version = traitlets.Unicode('^0.1.0').tag(sync=True) data = traitlets.Dict([]).tag(sync=True) config = traitlets.Dict(dict()).tag(sync=True)
class MultiToggleButtons(Box): description = traitlets.Unicode() value = traitlets.Tuple() options = traitlets.Union([traitlets.List(), traitlets.Dict()]) style = traitlets.Dict() def __init__(self, **kwargs): super().__init__(**kwargs) self._selection_obj = widget_selection._MultipleSelection() traitlets.link((self, 'options'), (self._selection_obj, 'options')) traitlets.link((self, 'value'), (self._selection_obj, 'value')) @observer(self, 'options') def _(*_): self.buttons = [ ToggleButton(description=label, layout=Layout(margin='1', width='auto')) for label in self._selection_obj._options_labels ] if self.description: self.label = Label( self.description, layout=Layout( width=self.style.get('description_width', '100px'))) else: self.label = Label( self.description, layout=Layout( width=self.style.get('description_width', '0px'))) self.children = [self.label] + self.buttons @observer(self.buttons, 'value') def _(*_): self.value = tuple(value for btn, value in zip( self.buttons, self._selection_obj._options_values) if btn.value) self.add_class('btn-group') def reset(self): opts = self.options self.options = [] self.options = opts def set_value(self, x): for b, opt in zip(self.buttons, self.options): b.value = (opt in x) def set_all_on(self): for b, opt in zip(self.buttons, self.options): b.value = True def set_all_off(self): for b, opt in zip(self.buttons, self.options): b.value = False
class MetaDefaults(Preprocessor): """ a preprocessor which enters default metadata tags into all cell metadata, without overriding any currently set """ nb_defaults = traits.Dict( default_value={}, help="dict of notebook level defaults").tag(config=True) cell_defaults = traits.Dict( default_value={}, help="dict of cell level defaults").tag(config=True) overwrite = traits.Bool( False, help="whether existing values should be overwritten").tag(config=True) def preprocess(self, nb, resources): logging.info("adding ipub defaults to notebook") for keys, val in flatten(self.nb_defaults).items(): dct = nb.metadata for key in keys[:-1]: if key not in dct: dct[key] = NotebookNode({}) dct = dct[key] if keys[-1] not in dct: dct[keys[-1]] = val elif self.overwrite: dct[keys[-1]] = val for cell in nb.cells: for keys, val in flatten(self.cell_defaults).items(): dct = cell.metadata leaf_not_dict = False for key in keys[:-1]: if key not in dct: dct[key] = NotebookNode({}) elif dct[key] is False and self.overwrite: dct[key] = NotebookNode({}) elif dct[key] is True: dct[key] = NotebookNode({}) elif not hasattr(dct[key], "items"): leaf_not_dict = True break dct = dct[key] if leaf_not_dict: pass elif keys[-1] not in dct: dct[keys[-1]] = val elif self.overwrite: dct[keys[-1]] = val return nb, resources
class DisplayManager(Trait): display = traitlets.Dict() state = traitlets.Dict() widgets = traitlets.List() def pre_execute(self): deleted = getattr(self.parent, '_last_parent', {}).get('metadata', {}).get('deletedCells', []) for key, displays in self.display.items() if deleted else []: self.display[key] = [ x for x in displays if x.id and x.id.display_id not in deleted ] def append(self, object): for key in object.vars or []: self.display[key] = self.display.get(key, []) self.display[key].append(object) self.state[key] = self.parent.user_ns.get(key, None) def pop(self, object): for key, values in self.display.items(): self.display[key] = [x for x in values if x is not object] def _post_execute_widget(self, object, change): with object.hold_trait_notifications(): self.post_execute() def post_execute(self): if not self.enabled: return update = { x: self.parent.user_ns.get(x, None) for x in self.display if x == "__test__" or nowidget.util.isinteractive(self.parent.user_ns.get(x, None)) or self.parent.user_ns.get(x, None) is not self.state.get(x, None) } for key, object in update.items(): if nowidget.util.isinteractive( object) and object not in self.widgets: object.observe( functools.partial(self._post_execute_widget, object)) self.widgets += [object] self.state.update(update) for object in set(sum([self.display[x] for x in update], [])): if not object.enabled: continue try: object.update(**self.state) except Exception as e: self.pop(object) sys.stderr.writelines(str(self.state)) sys.stderr.writelines(str(e).splitlines())
class PlotViewer(widgets.DOMWidget): """The time series visualization widget.""" _view_name = traitlets.Unicode('PlotView').tag(sync=True) _model_name = traitlets.Unicode('PlotModel').tag(sync=True) _view_module = traitlets.Unicode('tensorflow_model_analysis').tag( sync=True) _model_module = traitlets.Unicode('tensorflow_model-analysis').tag( sync=True) _view_module_version = traitlets.Unicode(VERSION_STRING).tag(sync=True) _model_module_version = traitlets.Unicode(VERSION_STRING).tag(sync=True) data = traitlets.Dict([]).tag(sync=True) config = traitlets.Dict(dict()).tag(sync=True)
class MeshData(SceneData): name = "mesh" data_source = traitlets.Instance(YTDataContainer) texture_objects = traitlets.Dict(trait=traitlets.Instance(Texture3D)) texture_objects = traitlets.Dict(trait=traitlets.Instance(Texture3D)) blocks = traitlets.Dict(default_value=()) scale = traitlets.Bool(False) size = traitlets.CInt(-1) def get_mesh_data(self, data_source, field): """ This reads the mesh data into a form that can be fed in to OpenGL. """ # get mesh information try: ftype, fname = field mesh_id = int(ftype[-1]) except ValueError: mesh_id = 0 mesh = data_source.ds.index.meshes[mesh_id - 1] offset = mesh._index_offset vertices = mesh.connectivity_coords indices = mesh.connectivity_indices - offset data = data_source[field] return triangulate_mesh(vertices, data, indices) def add_data(self, field): v, d, i = self.get_mesh_data(self.data_source, field) v.shape = (v.size // 3, 3) v = np.concatenate([v, np.ones((v.shape[0], 1))], axis=-1).astype("f4") d.shape = (d.size, 1) i.shape = (i.size, 1) i = i.astype("uint32") # d[:] = np.mgrid[0.0:1.0:1j*d.size].astype("f4")[:,None] self.vertex_array.attributes.append( VertexAttribute(name="model_vertex", data=v) ) self.vertex_array.attributes.append( VertexAttribute(name="vertex_data", data=d.astype("f4")) ) self.vertex_array.indices = i self.size = i.size @traitlets.default("vertex_array") def _default_vertex_array(self): return VertexArray(name="mesh_info", each=0)
class ContainerCard(v.VuetifyTemplate): _metadata = Dict(default_value=None, allow_none=True).tag(sync=True) @traitlets.default('template') def _template(self): return load_template('vue/card.vue') title = traitlets.Unicode(None, allow_none=True).tag(sync=True) subtitle = traitlets.Unicode(None, allow_none=True).tag(sync=True) text = traitlets.Unicode(None, allow_none=True).tag(sync=True) main = traitlets.Any().tag(sync=True, **widgets.widget_serialization) controls = traitlets.List().tag(sync=True, **widgets.widget_serialization) card_props = traitlets.Dict().tag(sync=True) main_props = traitlets.Dict().tag(sync=True) show_controls = traitlets.Bool(False).tag(sync=True)
class ColorMaps(ipywidgets.Widget): """Colormapping widget used to collect available colormaps """ _model_name = traitlets.Unicode('CMapModel').tag(sync=True) _model_module = traitlets.Unicode('@data-exp-lab/yt-widgets').tag(sync=True) _model_module_version = traitlets.Unicode(EXTENSION_VERSION).tag(sync=True) cmaps = traitlets.Dict({}).tag(sync=True, config=True) map_name = traitlets.Unicode('autumn').tag(sync=True, config=True) is_log = traitlets.Bool(False).tag(sync=True, config=True) min_val = traitlets.Float().tag(sync=True, config=True) max_val = traitlets.Float().tag(sync=True, config=True) generation = traitlets.Int(0).tag(sync=True, config=True) def __init__(self, *args, **kwargs): self.cmaps = self.get_mpl_cmaps() super(ColorMaps, self).__init__() def get_mpl_cmaps(self): """ Adds available colormaps from matplotlib.""" colormaps = {} import matplotlib.cm as mplcm cmap_list = mplcm.cmap_d.keys() for colormap in cmap_list: cmap = mplcm.get_cmap(colormap) vals = (cmap(np.mgrid[0.0:1.0:256j])*255).astype("uint8") # right now let's just flatten the arrays. Later we can # serialize each cmap on its own. table = vals.flatten().tolist() colormaps[colormap] = table return colormaps
class LabelEncoder(Transformer): '''Encode categorical columns with integer values between 0 and num_classes-1. Example: >>> import vaex >>> df = vaex.from_arrays(color=['red', 'green', 'green', 'blue', 'red']) >>> df # color 0 red 1 green 2 green 3 blue 4 red >>> encoder = vaex.ml.LabelEncoder(features=['color']) >>> encoder.fit_transform(df) # color label_encoded_color 0 red 2 1 green 1 2 green 1 3 blue 0 4 red 2 ''' # title = traitlets.Unicode(default_value='Label Encoder', read_only=True).tag(ui='HTML') prefix = traitlets.Unicode(default_value='label_encoded_', help=help_prefix).tag(ui='Text') labels_ = traitlets.Dict(default_value={}, allow_none=True, help='The encoded labels of each feature.').tag(output=True) allow_unseen = traitlets.Bool(default_value=False, allow_none=False, help='If True, unseen values will be \ encoded with -1, otherwise an error is raised').tag(ui='Checkbox') def fit(self, df): '''Fit LabelEncoder to the DataFrame. :param df: A vaex DataFrame. ''' for feature in self.features: labels = vaex.array_types.tolist(df[feature].unique()) self.labels_[feature] = dict(zip(labels, np.arange(len(labels)))) def transform(self, df): ''' Transform a DataFrame with a fitted LabelEncoder. :param df: A vaex DataFrame. Returns: :return copy: A shallow copy of the DataFrame that includes the encodings. :rtype: DataFrame ''' default_value = None if self.allow_unseen: default_value = -1 copy = df.copy() for feature in self.features: name = self.prefix + feature copy[name] = copy[feature].map(mapper=self.labels_[feature], default_value=default_value) return copy
class NodeEditorModel(ipywidgets.DOMWidget): _model_name = traitlets.Unicode("ReteEditorModel").tag(sync=True) _model_module = traitlets.Unicode("jupyterlab_nodeeditor").tag(sync=True) _model_module_version = traitlets.Unicode(EXTENSION_VERSION).tag(sync=True) _view_name = traitlets.Unicode("ReteEditorView").tag(sync=True) _view_module = traitlets.Unicode("jupyterlab_nodeeditor").tag(sync=True) _view_module_version = traitlets.Unicode(EXTENSION_VERSION).tag(sync=True) _components = traitlets.List(traitlets.Instance(Component)).tag( sync=True, **ipywidgets.widget_serialization) editorConfig = traitlets.Dict().tag(sync=True) selected_node = traitlets.Instance(NodeInstanceModel, allow_none=True).tag( sync=True, **ipywidgets.widget_serialization) nodes = traitlets.List(traitlets.Instance(NodeInstanceModel), default_value=[]).tag( sync=True, **ipywidgets.widget_serialization) def add_component(self, component): self._components = self._components + [component] def send_config(self, config): if isinstance(config, str): config = json.loads(config) self.send({"name": "setConfig", "args": [config]}) def sync_config(self): self.send({"name": "getConfig", "args": []})
class VisualizerBase(W.VBox): """ The basic Visualization class that takes the shape of an ipywidgets.VBox :param graph: an rdflib.graph.Graph object or a networkx.classes.graph.Graph object to visualize. :param edge_color: a string, the desired color of edges. :param node_color: a string, the desired color of nodes. :param selected_nodes: a tuple of URIRefs of nodes currently selected either via tap or box select. :param selected_edges: a list of edges currently selected, currently only working with ipycytoscape. """ graph = T.Union((T.Instance(Graph), T.Instance(nx.classes.graph.Graph)), allow_none=True) _vis = T.Instance(W.Box, allow_none=True) edge_color = T.Unicode(default_value="pink") node_color = T.Unicode(default_value="grey") selected_nodes = W.trait_types.TypedTuple(trait=T.Instance(URIRef)) selected_edges = T.List() hovered_nodes = W.trait_types.TypedTuple(trait=T.Instance(URIRef)) hovered_edges = T.List() graph_layout = T.Unicode() graph_layout_options = W.trait_types.TypedTuple(trait=T.Unicode()) graph_layout_params = T.Dict() @T.default("graph_layout_params") def make_params(self): return {}
class GenericInputs(Algorithm): """Base class for Algorithms that accept generic named inputs.""" inputs = tl.Dict(read_only=True) _repr_keys = ["inputs"] def _first_init(self, **kwargs): trait_names = self.trait_names() for key in kwargs: if key in trait_names and isinstance(kwargs[key], Node): raise RuntimeError( "Trait '%s' is reserved and cannot be used as an Generic Algorithm input" % key) input_keys = [ key for key in kwargs if key not in trait_names and isinstance(kwargs[key], Node) ] inputs = {key: kwargs.pop(key) for key in input_keys} self.set_trait("inputs", inputs) return super(GenericInputs, self)._first_init(**kwargs) @property def _base_definition(self): d = super(GenericInputs, self)._base_definition d["inputs"] = self.inputs return d
def __init__( self, trait_types=[tl.Dict(), tl.List(), tl.Enum(INTERPOLATION_METHODS), tl.Instance(InterpolationManager)], *args, **kwargs ): super(InterpolationTrait, self).__init__(trait_types=trait_types, *args, **kwargs)
class BasicJupyterToolbar(v.VuetifyTemplate): template = load_template('basic_jupyter_toolbar.vue', __file__) active_tool = traitlets.Instance(glue.viewers.common.tool.Tool, allow_none=True, default_value=None) tools_data = traitlets.Dict(default_value={}).tag(sync=True) active_tool_id = traitlets.Any().tag(sync=True) def __init__(self, viewer): self.output = viewer.output_widget self.tools = {} if viewer._default_mouse_mode_cls is not None: self._default_mouse_mode = viewer._default_mouse_mode_cls(viewer) self._default_mouse_mode.activate() else: self._default_mouse_mode = None super().__init__() @traitlets.observe('active_tool_id') def _on_change_v_model(self, change): if change.new is not None: if isinstance(self.tools[change.new], CheckableTool): self.active_tool = self.tools[change.new] else: # In this case it is a non-checkable tool and we should # activate it but not keep the tool checked in the toolbar self.tools[change.new].activate() self.active_tool_id = None else: self.active_tool = None @traitlets.observe('active_tool') def _on_change_active_tool(self, change): if change.old: change.old.deactivate() else: if self._default_mouse_mode: self._default_mouse_mode.deactivate() if change.new: change.new.activate() self.active_tool_id = change.new.tool_id else: self.active_tool_id = None if self._default_mouse_mode is not None: self._default_mouse_mode.activate() def add_tool(self, tool): self.tools[tool.tool_id] = tool # TODO: we should ideally just incorporate this check into icon_path directly. if os.path.exists(tool.icon): path = tool.icon else: path = icon_path(tool.icon, icon_format='svg') self.tools_data = { **self.tools_data, tool.tool_id: { 'tooltip': tool.tool_tip, 'img': read_icon(path, 'svg+xml') } }
class DataArray(ViewBase): """Will display a DataArray interactively, with an optional custom display_function. By default, it will simply display(...) the DataArray, using xarray's default display mechanism. """ model = traitlets.Instance(model.DataArray) clear_output = traitlets.Bool(True, help="Clear output each time the data changes") display_function = traitlets.Any(display) matplotlib_autoshow = traitlets.Bool(True, help="Will call plt.show() inside output context if open figure handles exist") numpy_errstate = traitlets.Dict({'all': 'ignore'}, help="Default numpy errstate during display to avoid showing error messsages, see :py:data:`numpy.errstate`_ ") def __init__(self, **kwargs): super().__init__(**kwargs) self.output = widgets.Output() self.output_data_array = widgets.Output() self.children = (self.progress_widget, self.output_data_array, self.output) self.model.observe(self.update_output, ['grid', 'grid_sliced']) self.update_output() def update_output(self, change=None): if self.clear_output: self.output_data_array.clear_output(wait=True) with self.output_data_array, np.errstate(**self.numpy_errstate): grid = self.model.grid_sliced if grid is None: grid = self.model.grid if grid is not None: self.display_function(grid) # make sure show is called inside the output widget if self.matplotlib_autoshow and 'matplotlib' in sys.modules: import matplotlib.pyplot as plt if plt.get_fignums(): plt.show()
class BaseLoader(W.Widget): """Base class for loaders. Uses the metadata format from FileUpload """ description = T.Unicode() graph = T.Instance(Graph) graph_id = T.Instance(BNode) file_upload_value = T.Dict() log = W.Output() @T.default("graph") def make_default_graph(self): return Graph() @T.default("graph_id") def make_default_graph_id(self): return self.graph.identifier @T.observe("file_upload_value") def process_files(self, change): """load a single graph from upload metadata TODO: support multiple graphs as a ConjunctiveGraph """ g = Graph() for file_name, data in change.new.items(): file_format = guess_format(file_name) g.parse(data=data["content"], format=file_format) self.graph = g self.graph_id = g.identifier
class Element(ipyt.Node): """A project element node compatible with ipytree.""" _identifier: str = trt.Unicode() _owner: str = trt.Unicode("self", allow_none=True) _type: str = trt.Unicode() _data: dict = trt.Dict()
class VersionSelectorWidget(ipw.VBox): """Class to choose app's version.""" disabled = traitlets.Bool() available_versions = traitlets.Dict(traitlets.Unicode()) def __init__(self, *args, **kwargs): style = {'description_width': '100px'} self.release_line = ipw.Dropdown( description='Release line', style=style, ) self.installed_version = ipw.Text( description='Installed version', disabled=True, style=style, ) self.info = StatusHTML('') super().__init__( children=[self.release_line, self.installed_version, self.info], layout={'min_width': '300px'}, *args, **kwargs, ) @traitlets.observe('disabled') def _observe_disabled(self, change): self.release_line.disabled = change['new']
class Remote(W.Widget): """a remote DVCS repository""" name = T.Unicode() url = T.Unicode() heads = T.Dict(value_trait=T.Unicode(), default_value=tuple()) auto_fetch = T.Bool(True) executor = ThreadPoolExecutor(max_workers=1) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if self.auto_fetch: self._on_auto_fetch() async def fetch(self): """fetch from the remote""" await self._fetch() self.heads = await self._update_heads() async def push(self, ref): """push to the remote""" await self._push(ref) @T.observe("auto_fetch") def _on_auto_fetch(self, _change=None): """handle changing the auto fetch preference""" if self.auto_fetch: IOLoop.current().add_callback(self.fetch)
class SlicingMetricsViewer(widgets.DOMWidget): """The slicing metrics visualization widget.""" _view_name = traitlets.Unicode('SlicingMetricsView').tag(sync=True) _model_name = traitlets.Unicode('SlicingMetricsModel').tag(sync=True) _view_module = traitlets.Unicode('tensorflow_model_analysis').tag( sync=True) _model_module = traitlets.Unicode('tensorflow_model_analysis').tag( sync=True) _view_module_version = traitlets.Unicode(VERSION_STRING).tag(sync=True) _model_module_version = traitlets.Unicode(VERSION_STRING).tag(sync=True) data = traitlets.List([]).tag(sync=True) config = traitlets.Dict(dict()).tag(sync=True) # Used for handling on the js side. event_handlers = {} js_events = traitlets.List([]).tag(sync=True) @traitlets.observe('js_events') def _handle_js_events(self, change): if self.js_events: if self.event_handlers: for event in self.js_events: event_name = event['name'] if event_name in self.event_handlers: self.event_handlers[event_name](event['detail']) # clears the event queue. self.js_events = []
class VirtualColumnEditor(v.VuetifyTemplate): df = traitlets.Any() editor = traitlets.Any() adder = traitlets.Any() on_close = traitlets.Any() column_name = traitlets.Unicode('mycolumn').tag(sync=True) components = traitlets.Dict(None, allow_none=True).tag( sync=True, **widgets.widget.widget_serialization) @traitlets.default('components') def _components(self): return {'editor': self.editor, 'adder': self.adder} @traitlets.default('editor') def _editor(self): return ExpressionTextArea(df=self.df, rows=1) @traitlets.default('adder') def _adder(self): return ColumnExpressionAdder(df=self.df, component=self.editor) template = traitlets.Unicode(''' <v-layout column style="position: relative"> <v-text-field placeholder="e.g. mycolumn" label="Column name" v-model='column_name' prepend-icon='edit'>test</v-text-field> <editor></editor> <div style="position: absolute; right: 20px; bottom: 30px; opacity: 0.8"> <adder></adder> </div> </v-layout>''').tag(sync=True) def save_column(self): if self.editor.valid: self.df[self.column_name] = self.editor.v_model if self.on_close: self.on_close()
class SelectionEditor(v.VuetifyTemplate): df = traitlets.Any() input = traitlets.Any() adder = traitlets.Any() on_close = traitlets.Any() components = traitlets.Dict(None, allow_none=True).tag( sync=True, **widgets.widget.widget_serialization) @traitlets.default('components') def _components(self): return {'component-input': self.input, 'adder': self.adder} @traitlets.default('input') def _input(self): return ExpressionSelectionTextArea(df=self.df) @traitlets.default('adder') def _adder(self): return ColumnSelectionAdder(df=self.df, component=self.input) template = traitlets.Unicode(''' <v-layout column> <component-input></component-input> <v-layout pa-4> <adder></adder> </v-layout> </v-layout>''').tag(sync=True)
class StateTransfer(HasState): state = traitlets.Dict() def transform(self, df): copy = df.copy() self.state = dict(self.state, active_range=[copy._index_start, copy._index_end]) copy.state_set(self.state) return copy
class VolumeWidget(ipywidgets.DOMWidget): _view_name = traitlets.Unicode("VolumeWidgetView").tag(sync=True) _view_module = traitlets.Unicode("ivvv").tag(sync=True) _view_module_version = traitlets.Unicode("1.0.0").tag(sync=True) image = ipydatawidgets.NDArray(numpy.zeros(0, dtype=numpy.uint8)).tag(sync=True, **ipydatawidgets.array_serialization) size = traitlets.Tuple().tag(sync=True) dimensions = traitlets.Dict().tag(sync=True) metadata = traitlets.Dict({"foo": "bar"}).tag(sync=True) density = traitlets.Float(0.1).tag(sync=True) brightness = traitlets.Float(0.1).tag(sync=True)
class Exchange(HasTraits): ccxt_args = traitlets.Dict() ccxt = ccxt.base.exchange.Exchange() def cancel_all_active_orders(self, ticker): open_orders = self.ccxt.fetch_open_orders(settings.trading.pair) for order in open_orders: self.ccxt.cancel_order(order['id'], ticker)
class Loader(Tool): default_node_opts: Optional[Dict[str, str]] = T.Dict(NODE_OPTS, allow_none=True) default_root_opts: Optional[Dict[str, str]] = T.Dict(ROOT_OPTS, allow_none=True) default_label_opts: Optional[Dict[str, str]] = T.Dict(LABEL_OPTS, allow_none=True) default_port_opts: Optional[Dict[str, str]] = T.Dict(PORT_OPTS, allow_none=True) default_edge_opts: Optional[Dict[str, str]] = T.Dict(EDGE_OPTS, allow_none=True) def load(self) -> MarkElementWidget: raise NotImplementedError("Subclasses should implement their behavior") def apply_layout_defaults(self, root: Node) -> Node: for el in index.iter_elements(root): if not el.layoutOptions: el.layoutOptions = self.get_default_opts(el) return root def get_default_opts(self, element: BaseElement) -> Dict: if isinstance(element, Node): if element.get_parent() is None: opts = self.default_root_opts else: opts = self.default_node_opts elif isinstance(element, Port): opts = self.default_port_opts elif isinstance(element, Label): opts = self.default_label_opts elif isinstance(element, Edge): opts = self.default_edge_opts if opts is None: return dict() else: return dict(**opts) def clear_defaults(self) -> "Loader": """Removes the current default layout options for the loader""" self.default_node_opts = None self.default_root_opts = None self.default_label_opts = None self.default_port_opts = None self.default_edge_opts = None return self
class XELKTypedLayout(OptionsWidget): selected = T.Any( default_value=ElkRoot ) # placeholder trait while playing with patterns value = ( T.Dict() ) # TODO get some typing around the dictionary e.g. Dict[Hashable, NEWDATACLASS] _type_map = { "Parents": "parents", "Node": ElkNode, "Label": ElkLabel, "Edge": ElkEdge, "Port": ElkPort, } def __init__(self, *args, **kwargs): groups = [] for title, element_type in self._type_map.items(): group = [] for identifier, cls_widget in self._collect_type_options().items(): if cls_widget.matches(element_type): group.append(cls_widget()) option_group = OptionsWidget(options=group) option_group.identifier = element_type option_group.title = title option_group.observe(self._update_value, "value") groups.append(option_group) self.options = groups super().__init__(*args, **kwargs) self.children = self._ui() def _collect_type_options(self): return type_options(LayoutOptionWidget) def _update_value(self, change: T.Bunch = None): if change and change.new: self.value[self.selected][change.owner.identifier] = change.new else: self.value[self.selected] = { opt.identifier: opt.value for opt in self.options } self._notify_trait("value", {}, self.value) def get(self, element_type) -> OptionsWidget: """Get the `OptionsWidget` for the given element_type according to the current active selection """ for option in self.options: if option.identifier == element_type: return option raise KeyError(f"`{element_type}` is not a valid element for this widget")
class OptionsWidget(W.Accordion, LayoutOptionWidget): identifier = T.Any() options: List["OptionsWidget"] = T.List() value: Dict = T.Dict() @T.observe("options") def _update_options(self, change: T.Bunch = None): if change and change.old is not T.Undefined: for old_option in change.old: old_option.unobserve(self._update_value, "value") for option in self.options: option.observe(self._update_value, "value") if self.children: self.children = self.options def _ui(self): # loop over options and build their UI if required for i, option in enumerate(self.options): if not option.children: option.children = option._ui() title = option.title if title is None: title = re.sub(r"(\w)([A-Z])", r"\1 \2", option.__class__.__name__) self.set_title(i, title) return self.options def _update_value(self, change: T.Bunch = None): value = {} for option in self.options: if option.value is not None: value[option.identifier] = option.value self.value = value def get(self, key: Union[str, Type[LayoutOptionWidget]]) -> LayoutOptionWidget: """Get the `LayoutOptionWidget` instance in for this option group for the given key :param key: Key to lookup option :type key: Union[str, Type[LayoutOptionWidget]] :raises KeyError: [description] :return: Instance of the associated layout option widget :rtype: LayoutOptionWidget """ identifier = key try: if issubclass(key, LayoutOptionWidget): identifier = key.identifier except TypeError: pass # okay if key is not a class for option in self.options: if option.identifier == identifier: return option raise KeyError(f"`{key}` is not a valid option for this widget")