class _SliderBase(Widget): bar_color = param.Color(default="#e6e6e6", doc=""" Color of the slider bar as a hexidecimal RGB value.""") callback_policy = param.ObjectSelector( default='continuous', objects=['continuous', 'throttle', 'mouseup'], doc=""" Policy to determine when slider events are triggered: * "continuous": the callback will be executed immediately for each movement of the slider * "throttle": the callback will be executed at most every ``callback_throttle`` milliseconds. * "mouseup": the callback will be executed only once when the slider is released. """) callback_throttle = param.Integer(default=200, doc=""" Number of milliseconds to pause between callback calls as the slider is moved.""") direction = param.ObjectSelector(default='ltr', objects=['ltr', 'rtl'], doc=""" Whether the slider should go from left-to-right ('ltr') or right-to-left ('rtl')""") orientation = param.ObjectSelector(default='horizontal', objects=['horizontal', 'vertical'], doc=""" Whether the slider should be oriented horizontally or vertically.""") show_value = param.Boolean(default=True, doc=""" Whether to show the widget value""") tooltips = param.Boolean(default=True, doc=""" Whether the slider handle should display tooltips""") _widget_type = _BkSlider __abstract = True
class CurveExample(hv.streams.Stream): color = param.Color(default='#000000', precedence=0) element = param.ObjectSelector(default=hv.Curve, objects=[hv.Curve, hv.Scatter, hv.Area], precedence=0) amplitude = param.Number(default=2, bounds=(2, 5)) frequency = param.Number(default=2, bounds=(1, 10)) output = parambokeh.view.Plot() def view(self, *args, **kwargs): return self.element( self.amplitude * np.sin(np.linspace(0, np.pi * self.frequency)), vdims=[hv.Dimension('y', range=(-5, 5))])(style=dict(color=self.color)) def event(self, **kwargs): if not self.output or any(k in kwargs for k in ['color', 'element']): self.output = hv.DynamicMap(self.view, streams=[self]) else: super(CurveExample, self).event(**kwargs)
class _SliderBase(Widget): bar_color = param.Color(default="#e6e6e6", doc=""" Color of the slider bar as a hexidecimal RGB value.""") direction = param.ObjectSelector(default='ltr', objects=['ltr', 'rtl'], doc=""" Whether the slider should go from left-to-right ('ltr') or right-to-left ('rtl')""") orientation = param.ObjectSelector(default='horizontal', objects=['horizontal', 'vertical'], doc=""" Whether the slider should be oriented horizontally or vertically.""") show_value = param.Boolean(default=True, doc=""" Whether to show the widget value.""") tooltips = param.Boolean(default=True, doc=""" Whether the slider handle should display tooltips.""") _widget_type = _BkSlider __abstract = True def __init__(self, **params): if 'value' in params and 'value_throttled' in self.param: params['value_throttled'] = params['value'] super(_SliderBase, self).__init__(**params)
class _SliderBase(Widget): bar_color = param.Color(default="#e6e6e6", doc=""" Color of the slider bar as a hexidecimal RGB value.""") direction = param.ObjectSelector(default='ltr', objects=['ltr', 'rtl'], doc=""" Whether the slider should go from left-to-right ('ltr') or right-to-left ('rtl')""" ) orientation = param.ObjectSelector(default='horizontal', objects=['horizontal', 'vertical'], doc=""" Whether the slider should be oriented horizontally or vertically.""") show_value = param.Boolean(default=True, doc=""" Whether to show the widget value""") tooltips = param.Boolean(default=True, doc=""" Whether the slider handle should display tooltips""") _widget_type = _BkSlider __abstract = True
class ColorPicker(Widget): value = param.Color(default=None, doc=""" The selected color""") _widget_type = _BkColorPicker _rename = {'value': 'color', 'name': 'title'}
class _SliderBase(Widget): bar_color = param.Color(default="#e6e6e6", doc=""" Color of the slider bar as a hexidecimal RGB value.""") direction = param.ObjectSelector(default='ltr', objects=['ltr', 'rtl'], doc=""" Whether the slider should go from left-to-right ('ltr') or right-to-left ('rtl').""") name = param.String(default=None, doc=""" The name of the widget. Also used as the label of the widget. If not set, the widget has no label.""") orientation = param.ObjectSelector(default='horizontal', objects=['horizontal', 'vertical'], doc=""" Whether the slider should be oriented horizontally or vertically.""") show_value = param.Boolean(default=True, doc=""" Whether to show the widget value as a label or not.""") tooltips = param.Boolean(default=True, doc=""" Whether the slider handle should display tooltips.""") _widget_type = _BkSlider __abstract = True def __init__(self, **params): if 'value' in params and 'value_throttled' in self.param: params['value_throttled'] = params['value'] super().__init__(**params) def __repr__(self, depth=0): return '{cls}({params})'.format( cls=type(self).__name__, params=', '.join(param_reprs(self, ['value_throttled']))) def _process_property_change(self, msg): if config.throttled: if "value" in msg: del msg["value"] if "value_throttled" in msg: msg["value"] = msg["value_throttled"] return super()._process_property_change(msg) def _update_model(self, events, msg, root, model, doc, comm): if 'value_throttled' in msg: del msg['value_throttled'] return super()._update_model(events, msg, root, model, doc, comm)
class _BigDumbParams(param.Parameterized): action = param.Action(default_action, allow_None=True) array = param.Array(np.array([1.0, 2.0])) boolean = param.Boolean(True, allow_None=True) callable = param.Callable(default_action, allow_None=True) class_selector = param.ClassSelector(int, is_instance=False, allow_None=True) color = param.Color("#FFFFFF", allow_None=True) composite = param.Composite(["action", "array"], allow_None=True) try: data_frame = param.DataFrame( pd.DataFrame({"A": 1.0, "B": np.arange(5)}), allow_None=True ) except TypeError: data_frame = param.DataFrame(pd.DataFrame({"A": 1.0, "B": np.arange(5)})) date = param.Date(datetime.now(), allow_None=True) date_range = param.DateRange((datetime.min, datetime.max), allow_None=True) dict_ = param.Dict({"foo": "bar"}, allow_None=True, doc="dict means dictionary") dynamic = param.Dynamic(default=default_action, allow_None=True) file_selector = param.FileSelector( os.path.join(FILE_DIR_DIR, "LICENSE"), path=os.path.join(FILE_DIR_DIR, "*"), allow_None=True, ) filename = param.Filename( os.path.join(FILE_DIR_DIR, "LICENSE"), allow_None=True ) foldername = param.Foldername(os.path.join(FILE_DIR_DIR), allow_None=True) hook_list = param.HookList( [CallableObject(), CallableObject()], class_=CallableObject, allow_None=True ) integer = param.Integer(10, allow_None=True) list_ = param.List([1, 2, 3], allow_None=True, class_=int) list_selector = param.ListSelector([2, 2], objects=[1, 2, 3], allow_None=True) magnitude = param.Magnitude(0.5, allow_None=True) multi_file_selector = param.MultiFileSelector( [], path=os.path.join(FILE_DIR_DIR, "*"), allow_None=True, check_on_set=True, ) number = param.Number(-10.0, allow_None=True, doc="here is a number") numeric_tuple = param.NumericTuple((5.0, 10.0), allow_None=True) object_selector = param.ObjectSelector( False, objects={"False": False, "True": 1}, allow_None=True ) path = param.Path(os.path.join(FILE_DIR_DIR, "LICENSE"), allow_None=True) range_ = param.Range((-1.0, 2.0), allow_None=True) series = param.Series(pd.Series(range(5)), allow_None=True) string = param.String("foo", allow_None=True, doc="this is a string") tuple_ = param.Tuple((3, 4, "fi"), allow_None=True) x_y_coordinates = param.XYCoordinates((1.0, 2.0), allow_None=True)
class StyleApp(param.Parameterized): color = param.Color(default="#000000") view = param.Parameter() def __init__(self, **params): super().__init__(**params) self._html_pane = pn.pane.HTML(height=100, width=100) self.view = pn.Column(self._html_pane, self.param.color) self._update_style() @param.depends("color", watch=True) def _update_style(self, *events): self._html_pane.style = {"background-color": self.color}
class ColorPicker(Widget): """ The `ColorPicker` widget allows selecting a hexidecimal RGB color value using the browser’s color-picking widget. Reference: https://panel.holoviz.org/reference/widgets/ColorPicker.html :Example: >>> ColorPicker(name='Color', value='#99ef78') """ value = param.Color(default=None, doc=""" The selected color""") _widget_type = _BkColorPicker _rename = {'value': 'color', 'name': 'title'}
class Example(BaseClass): """An example Parameterized class""" timestamps = [] boolean = param.Boolean(True, doc="A sample Boolean parameter") color = param.Color(default="#FFFFFF") date = param.Date(dt.date(2017, 1, 1), bounds=wired.DATE_BOUNDS) dataframe = param.DataFrame(pd.util.testing.makeDataFrame().iloc[:3]) select_string = param.ObjectSelector(default="yellow", objects=["red", "yellow", "green"]) select_fn = param.ObjectSelector(default=list, objects=[list, set, dict]) int_list = param.ListSelector(default=[3, 5], objects=[1, 3, 5, 7, 9], precedence=0.5) single_file = param.FileSelector(path="../../*/*.py*", precedence=0.5) multiple_files = param.MultiFileSelector(path="../../*/*.py?", precedence=0.5) record_timestamp = param.Action( lambda x: x.timestamps.append(dt.datetime.utcnow()), doc="""Record timestamp.""", precedence=0.7, )
class Notification(param.Parameterized): background = param.Color(default=None) duration = param.Integer(default=3000, constant=True) icon = param.String(default=None) message = param.String(default='', constant=True) notification_area = param.Parameter(constant=True, precedence=-1) notification_type = param.String(default=None, constant=True, label='type') _destroyed = param.Boolean(default=False) def destroy(self): from .notebook import push_on_root self._destroyed = True for ref in self.notification_area._models: push_on_root(ref)
class MyParameterized(param.Parameterized): enable = param.Boolean(True, doc="A sample Boolean parameter", allow_None=True) what_proportion = param.Magnitude(default=0.9) age = param.Number(49, bounds=(0, 100), doc="Any Number between 0 to 100") how_many = param.Integer() favorite_quote = param.String(default="Hello, world!") choose_file_or_folder = param.Path(search_paths='./') choose_folder = param.Foldername(search_paths="./") choose_file = param.Filename(search_paths="./") select_a_file = param.FileSelector(path='./*') select_multiple_files = param.MultiFileSelector(path='./*') favorite_color = param.ObjectSelector( default="green", objects=["red", "yellow", "green"]) favorite_fruit = param.Selector(default="Apple", objects=["Orange", "Apple", "Mango"]) select_multiple = param.ListSelector(default=[3, 5], objects=[1, 2, 3, 4, 5]) birthday = param.CalendarDate(dt.date(2017, 1, 1), bounds=(dt.date(2017, 1, 1), dt.date(2017, 2, 1))) appointment = param.Date(dt.datetime(2017, 1, 1), bounds=(dt.datetime(2017, 1, 1), dt.datetime(2017, 2, 1))) least_favorite_color = param.Color(default='#FF0000') dataset = param.DataFrame(pd.util.testing.makeDataFrame().iloc[:3]) this_strange_thing = param.Tuple(default=(False, ), allow_None=True) some_numbers = param.NumericTuple(default=(1, 2, 3.0, 4.0)) home_city = param.XYCoordinates(default=(-111.65, 40.23)) bounds = param.Range(default=(-10, 10))
class link_selections(_base_link_selections): """ Operation which automatically links selections between elements in the supplied HoloViews object. Can be used a single time or be used as an instance to apply the linked selections across multiple objects. """ cross_filter_mode = param.Selector(['overwrite', 'intersect'], default='intersect', doc=""" Determines how to combine selections across different elements.""") index_cols = param.List(default=None, doc=""" If provided, selection switches to index mode where all queries are expressed solely in terms of discrete values along the index_cols. All Elements given to link_selections must define the index_cols, either as explicit dimensions or by sharing an underlying Dataset that defines them.""" ) selection_expr = param.Parameter(default=None, doc=""" dim expression of the current selection or None to indicate that everything is selected.""") selected_color = param.Color(default=None, allow_None=True, doc=""" Color of selected data, or None to use the original color of each element.""") selection_mode = param.Selector( ['overwrite', 'intersect', 'union', 'inverse'], default='overwrite', doc=""" Determines how to combine successive selections on the same element.""") unselected_alpha = param.Magnitude(default=0.1, doc=""" Alpha of unselected data.""") unselected_color = param.Color(default=None, doc=""" Color of unselected data.""") @bothmethod def instance(self_or_cls, **params): inst = super(link_selections, self_or_cls).instance(**params) # Initialize private properties inst._obj_selections = {} inst._obj_regions = {} inst._reset_regions = True # _datasets caches inst._datasets = [] inst._cache = {} self_or_cls._install_param_callbacks(inst) return inst @param.depends('selection_expr', watch=True) def _update_pipes(self): sel_expr = self.selection_expr for pipe, ds, raw in self._datasets: ref = ds._plot_id self._cache[ref] = ds_cache = self._cache.get(ref, {}) if sel_expr in ds_cache: data = ds_cache[sel_expr] return pipe.event(data=data.data) else: ds_cache.clear() sel_ds = SelectionDisplay._select(ds, sel_expr, self._cache) ds_cache[sel_expr] = sel_ds pipe.event(data=sel_ds.data if raw else sel_ds) def selection_param(self, data): """ Returns a parameter which reflects the current selection when applied to the supplied data, making it easy to create a callback which depends on the current selection. Args: data: A Dataset type or data which can be cast to a Dataset Returns: A parameter which reflects the current selection """ raw = False if not isinstance(data, Dataset): raw = True data = Dataset(data) pipe = Pipe(data=data.data) self._datasets.append((pipe, data, raw)) return pipe.param.data @bothmethod def _install_param_callbacks(self_or_cls, inst): def update_selection_mode(*_): # Reset selection state of streams for stream in inst._selection_expr_streams.values(): stream.reset() stream.mode = inst.selection_mode inst.param.watch(update_selection_mode, ['selection_mode']) def update_cross_filter_mode(*_): inst._cross_filter_stream.reset() inst._cross_filter_stream.mode = inst.cross_filter_mode inst.param.watch(update_cross_filter_mode, ['cross_filter_mode']) def update_show_region(*_): for stream in inst._selection_expr_streams.values(): stream.include_region = inst.show_regions stream.event() inst.param.watch(update_show_region, ['show_regions']) def update_selection_expr(*_): new_selection_expr = inst.selection_expr current_selection_expr = inst._cross_filter_stream.selection_expr if repr(new_selection_expr) != repr(current_selection_expr): # Disable regions if setting selection_expr directly if inst.show_regions: inst.show_regions = False inst._selection_override.event( selection_expr=new_selection_expr) inst.param.watch(update_selection_expr, ['selection_expr']) def selection_expr_changed(*_): new_selection_expr = inst._cross_filter_stream.selection_expr if repr(inst.selection_expr) != repr(new_selection_expr): inst.selection_expr = new_selection_expr inst._cross_filter_stream.param.watch(selection_expr_changed, ['selection_expr']) # Clear selection expr sequence history on plot reset for stream in inst._selection_expr_streams.values(): def clear_stream_history(resetting, stream=stream): if resetting: stream.clear_history() print("registering reset for ", stream) stream.plot_reset_stream.param.watch(clear_stream_history, ['resetting']) @classmethod def _build_selection_streams(cls, inst): # Colors stream style_stream = _Styles( colors=[inst.unselected_color, inst.selected_color], alpha=inst.unselected_alpha) # Cmap streams cmap_streams = [ _Cmap(cmap=inst.unselected_cmap), _Cmap(cmap=inst.selected_cmap), ] def update_colors(*_): colors = [inst.unselected_color, inst.selected_color] style_stream.event(colors=colors, alpha=inst.unselected_alpha) cmap_streams[0].event(cmap=inst.unselected_cmap) if cmap_streams[1] is not None: cmap_streams[1].event(cmap=inst.selected_cmap) inst.param.watch( update_colors, ['unselected_color', 'selected_color', 'unselected_alpha']) # Exprs stream exprs_stream = _SelectionExprLayers(inst._selection_override, inst._cross_filter_stream) return _SelectionStreams( style_stream=style_stream, exprs_stream=exprs_stream, cmap_streams=cmap_streams, ) @property def unselected_cmap(self): """ The datashader colormap for unselected data """ if self.unselected_color is None: return None return _color_to_cmap(self.unselected_color) @property def selected_cmap(self): """ The datashader colormap for selected data """ return None if self.selected_color is None else _color_to_cmap( self.selected_color)
class PDBeMolStar(ReactiveHTML): """PDBe MolStar structure viewer. Set one of `molecule_id`, `custom_data` and `ligand_view`. For more information: - https://github.com/PDBeurope/pdbe-molstar/wiki - https://molstar.org/ The implementation is based on the JS Plugin. See - https://github.com/PDBeurope/pdbe-molstar/wiki/1.-PDBe-Molstar-as-JS-plugin For documentation on the helper methods: - https://github.com/molstar/pdbe-molstar/wiki/3.-Helper-Methods """ molecule_id = param.String(default=None, doc="PDB id to load. Example: '1qyn' or '1cbs'") custom_data = param.Dict( doc="""Load data from a specific data source. Example: { "url": "https://www.ebi.ac.uk/pdbe/coordinates/1cbs/chains?entityId=1&asymId=A&encoding=bcif", "format": "cif", "binary": True } """) ligand_view = param.Dict( doc= """This option can be used to display the PDBe ligand page 3D view like https://www.ebi.ac.uk/pdbe/entry/pdb/1cbs/bound/REA. Example: {"label_comp_id": "REA"} """) alphafold_view = param.Boolean( default=False, doc= "Applies AlphaFold confidence score colouring theme for alphafold model" ) assembly_id = param.String(doc="Specify assembly") # Todo: figure out if `background` could/ should be used bg_color = param.Color( "#F7F7F7", doc= "Color of the background. If `None`, colors default is chosen depending on the color theme", ) highlight_color = param.Color(default="#ff6699", doc="Color for mouseover highlighting") select_color = param.Color(default="#0c0d11", doc="Color for selections") visual_style = param.Selector(default=None, objects=[None, *REPRESENTATIONS], doc="Visual styling") # Todo: Determine if it should be default or light theme theme = param.Selector(default="default", objects=["default", "dark"], doc="CSS theme to use") hide_polymer = param.Boolean(default=False, doc="Hide polymer") hide_water = param.Boolean(default=False, doc="Hide water") hide_heteroatoms = param.Boolean(default=False, doc="Hide het") hide_carbs = param.Boolean(default=False, doc="Hide carbs") hide_non_standard = param.Boolean(default=False, doc="Hide non standard") hide_coarse = param.Boolean(default=False, doc="Hide coarse") hide_controls_icon = param.Boolean(default=False, doc="Hide the control menu") hide_expand_icon = param.Boolean(default=False, doc="Hide the expand icon") hide_settings_icon = param.Boolean(default=False, doc="Hide the settings menu") hide_selection_icon = param.Boolean( default=False, doc="Hide the selection icon" # Default False, set False/True for True ) # Todo requires testing with a trajectory file hide_animation_icon = param.Boolean(default=False, doc="Hide the animation icon") pdbe_url = param.String( default=None, constant=True, doc="Url for PDB data. Mostly used for internal testing") load_maps = param.Boolean( default=False, doc="Load electron density maps from the pdb volume server") validation_annotation = param.Boolean( default=False, doc="Adds 'annotation' control in the menu") domain_annotation = param.Boolean( default=False, doc="Adds 'annotation' control in the menu") low_precision_coords = param.Boolean( default=False, doc="Load low precision coordinates from the model server") hide_controls = param.Boolean(default=True, doc="Hide the control menu") expanded = param.Boolean(default=False, doc="""Display full-screen by default on load""") landscape = param.Boolean( default= True, # Changed to True because it works best with Panel currently doc= """Set landscape view. The controls will similar to the full-screen view""", ) select_interaction = param.Boolean( default=True, doc="Switch on or off the default selection interaction behaviour") lighting = param.Selector( default="matte", objects=["flat", "matte", "glossy", "metallic", "plastic"], doc="Set the lighting", ) default_preset = param.Selector( default="default", objects=["default", "unitcell", "all-models", "supercell"], doc="Set the preset view", ) pdbe_link = param.Boolean( default=True, doc="Show the PDBe entry link at in the top right corner") spin = param.Boolean(default=False, doc="Toggle spin") _clear_highlight = param.Boolean( doc="Event to trigger clearing of highlights") _select = param.Dict( doc="Dictionary used for selections and coloring these selections") _clear_selection = param.Boolean(doc="Clear selection event trigger") _highlight = param.Dict( doc="Dictionary used for selections and coloring these selections") _reset = param.Boolean(doc="Reset event trigger") _args = param.Dict(doc="Dictionary with function call arguments") test = param.Boolean(default=False) _template = """ <link id="molstarTheme" rel="stylesheet" type="text/css" href="https://www.ebi.ac.uk/pdbe/pdb-component-library/css/pdbe-molstar-1.2.1.css"/> <div id="container" style="width:100%; height: 100%;"><div id="pdbeViewer"></div></div> """ __javascript__ = [ "https://www.ebi.ac.uk/pdbe/pdb-component-library/js/pdbe-molstar-plugin-1.2.1.js", ] _scripts = { "render": """ function standardize_color(str){ var ctx = document.createElement("canvas").getContext("2d"); ctx.fillStyle = str; return ctx.fillStyle; } function toRgb(color) { var hex = standardize_color(color) var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : null; } state.toRgb = toRgb function getHideStructure(){ var hideStructure = []; if (data.hide_polymer){ hideStructure.push("polymer") } if (data.hide_water){ hideStructure.push("water") } if (data.hide_heteroatoms){ hideStructure.push("het") } if (data.hide_carbs){ hideStructure.push("carbs") } if (data.hide_non_standard){ hideStructure.push("nonStandard") } if (data.hide_coarse){ hideStructure.push("coarse") } return hideStructure } function getHideCanvasControls(){ var hideCanvasControls = []; if (data.hide_controls_icon){ hideCanvasControls.push("controlToggle") } if (data.hide_expand_icon){ hideCanvasControls.push("expand") } if (data.hide_settings_icon){ hideCanvasControls.push("controlInfo") } if (data.hide_selection_icon){ hideCanvasControls.push('selection') } if (data.hide_animation_icon){ hideCanvasControls.push("animation") } return hideCanvasControls } state.getHideCanvasControls = getHideCanvasControls function getOptions(){ var options = { moleculeId: data.molecule_id, customData: data.custom_data, ligandView: data.ligand_view, alphafoldView: data.alphafold_view, assemblyId: data.assembly_id, bgColor: toRgb(data.bg_color), highlightColor: toRgb(data.highlight_color), selectColor: toRgb(data.select_color), hideStructure: getHideStructure(), hideCanvasControls: getHideCanvasControls(), loadMaps: data.load_maps, validationAnnotation: data.validation_annotation, domainAnnotation: data.domain_annotation, lowPrecisionCoords: data.low_precision_coords, expanded: data.expanded, hideControls: data.hide_controls, landscape: data.landscape, selectInteraction: data.select_interaction, lighting: data.lighting, defaultPreset: data.default_preset, pdbeLink: data.pdbe_link, } if (data.visual_style!==null){ options["visualStyle"]=data.visual_style } if (data.pdbe_url!==null){ options["pdbeUrl"]=data.pdbe_url } return options } state.getOptions=getOptions self.theme() state.viewerInstance = new PDBeMolstarPlugin(); state.viewerInstance.render(pdbeViewer, state.getOptions()); """, "rerender": """ state.viewerInstance.visual.update(state.getOptions(), fullLoad=true) """, "molecule_id": """self.rerender()""", "custom_data": """self.rerender()""", "ligand_view": """self.rerender()""", "alphafold_view": """self.rerender()""", "assembly_id": """self.rerender()""", "visual_style": """self.rerender()""", "bg_color": "state.viewerInstance.canvas.setBgColor(state.toRgb(data.bg_color))", "highlight_color": """ state.viewerInstance.visual.setColor({highlight: state.toRgb(data.highlight_color)})""", "select_color": """ state.viewerInstance.visual.setColor({select: state.toRgb(data.select_color)})""", "theme": """ if (data.theme==="dark"){ molstarTheme.href="https://www.ebi.ac.uk/pdbe/pdb-component-library/css/pdbe-molstar-1.2.1.css" } else { molstarTheme.href="https://www.ebi.ac.uk/pdbe/pdb-component-library/css/pdbe-molstar-light-1.2.1.css" } """, "hide_polymer": "state.viewerInstance.visual.visibility({polymer:!data.hide_polymer})", "hide_water": "state.viewerInstance.visual.visibility({water:!data.hide_water})", "hide_heteroatoms": "state.viewerInstance.visual.visibility({het:!data.hide_heteroatoms})", "hide_carbs": "state.viewerInstance.visual.visibility({carbs:!data.hide_carbs})", "hide_non_standard": "state.viewerInstance.visual.visibility({nonStandard:!data.hide_non_standard})", "hide_coarse": "state.viewerInstance.visual.visibility({coarse:!data.hide_coarse})", "hide_controls_icon": """self.rerender()""", "hide_expand_icon": """self.rerender()""", "hide_settings_icon": """self.rerender()""", "hide_selection_icon": """self.rerender()""", "hide_animation_icon": """self.rerender()""", "load_maps": "self.rerender()", "validation_annotation": """self.rerender()""", "domain_annotation": """self.rerender()""", "low_precision_coords": """self.rerender()""", "expanded": "state.viewerInstance.canvas.toggleExpanded(data.expanded)", "landscape": """self.rerender()""", "select_interaction": """self.rerender()""", "lighting": """self.rerender()""", "default_preset": """self.rerender()""", "pdbe_link": """self.rerender()""", "hide_controls": "state.viewerInstance.canvas.toggleControls(!data.hide_controls);", "spin": """state.viewerInstance.visual.toggleSpin(data.spin);""", "_select": """ console.log(data._select); if(data._select) { state.viewerInstance.visual.select(data._select); } """, "_clear_selection": """ state.viewerInstance.visual.clearSelection(data._args['number']); """, "_highlight": """ if(data._highlight) { state.viewerInstance.visual.highlight(data._highlight); }; """, "_clear_highlight": """ state.viewerInstance.visual.clearHighlight(); """, "_reset": """ state.viewerInstance.visual.reset(data._args['data'])""", "resize": "state.viewerInstance.canvas.handleResize()", } def color(self, data, non_selected_color=None): """ Alias for PDBE Molstar's `select` method. See https://github.com/molstar/pdbe-molstar/wiki/3.-Helper-Methods for parameter details :param data: List of dicts :param non_selected_color: Dict of color example: {'r':255, 'g':215, 'b': 0} :return: None """ self._select = {"data": data, "nonSelectedColor": non_selected_color} self._select = None def clear_selection(self, structure_number=None): """ Clear selection See https://github.com/molstar/pdbe-molstar/wiki/3.-Helper-Methods for parameter details. :param structure_number: Optional integer to specify structure number :return: """ self._args = {"number": structure_number} self._clear_selection = not self._clear_selection def highlight(self, data): """ Trigger highlight See https://github.com/molstar/pdbe-molstar/wiki/3.-Helper-Methods for parameter details. :param data: List of dicts :return: None """ self._highlight = {"data": data} self._highlight = None def clear_highlight(self): """Clears the current highlight""" self._clear_highlight = not self._clear_highlight def reset(self, data): """ Reset to defaults See https://github.com/molstar/pdbe-molstar/wiki/3.-Helper-Methods for parameter details. :param data: Dictionary of options to reset to defaults :return: """ self._args = {"data": data} self._reset = not self._reset def _load_complete(self, event): print('aww yeah')
class Stylesheet(pn.pane.HTML): """The Material `Stylesheet` can be included in your app if you want to have customized styles for your widgets and panes. The styles are based on [Material Design](https://material.io/design) and the [MWC](https://github.com/material-components/material-components-web-components) implementation. As an example you can set the `primary_color` and this corresponds to the `--mdc-theme-primary` css value. The Stylesheet `.editor` parameter provides an interactive stylesheet editor. """ primary_color = param.Color(default="#4caf50") primary_on_color = param.Color(default="#000000") secondary_color = param.Color(default="#9c27b0") secondary_on_color = param.Color(default="#ffffff") error_color = param.Color(default="#f44336") error_on_color = param.Color(default="#000000") reset_to_defaults = param.Action() editor = param.Parameter(doc="An interactive style editor component") # Needed for inheritance to work priority = 0 _rename = {**pn.pane.HTML._rename, **_STYLEPANE_RENAME} def __init__(self, **params): params["height"] = 0 params["width"] = 0 params["sizing_mode"] = "fixed" params["margin"] = 0 super().__init__(**params) self.editor = pn.WidgetBox(pn.Param( self, parameters=(_SETTINGS_PARAMETERS), ), name="Material StyleSheet Editor") self.reset_to_defaults = self._reset_to_defaults self._handle_style_parameter_change() # Don't name the function # `_update`, `_update_object_from_parameters`, `_update_model` or `_update_pane` # as this will override a function in the parent class. @param.depends(*_STYLE_PARAMETERS, watch=True) def _handle_style_parameter_change(self, *_): self.object = f""" <style> :root {{ --mdc-theme-primary: {self.primary_color}; --mdc-theme-on-primary: {self.primary_on_color}; --mdc-theme-secondary: {self.secondary_color}; --mdc-theme-on-secondary: {self.secondary_on_color}; --mdc-theme-error: {self.error_color}; --mdc-theme-on-error: {self.error_on_color}; --mdc-typography-button-font-size: 1.33rem; }} body {{ font-family: roboto; font-size: 14px; }} mwc-circular-progress {{ margin-left: auto; margin-right: auto; display: block; }} mwc-button.secondary, mwc-linear-progress.secondary, mwc-circular-progress.secondary {{ --mdc-theme-primary: {self.secondary_color}; --mdc-theme-on-primary: {self.secondary_on_color}; }} mwc-button.warning, mwc-button.danger, mwc-linear-progress.warning, mwc-linear-progress.danger, mwc-circular-progress.warning, mwc-circular-progress.danger {{ --mdc-theme-primary: {self.error_color}; --mdc-theme-on-primary: {self.error_on_color}; }} mwc-button.light, mwc-linear-progress.light, mwc-circular-progress.light {{ --mdc-theme-primary: #fafafa; --mdc-theme-on-primary: black; }} mwc-button.dark, mwc-linear-progress.dark, mwc-circular-progress.dark {{ --mdc-theme-primary: #212121; --mdc-theme-on-primary: white; }} </style> """ def _reset_to_defaults(self, *_): defaults = {p: self.param[p].default for p in _STYLE_PARAMETERS} self.param.set_param(**defaults) # Needed to avoid infinite recursion def __str__(self): return "Stylesheet()" def __repr__(self, depth=0): # pylint: disable=unused-argument return "Stylesheet()"
class link_selections(_base_link_selections): selection_expr = param.Parameter(default=None) unselected_color = param.Color(default="#99a6b2") # LightSlateGray - 65% selected_color = param.Color(default="#DC143C") # Crimson @classmethod def _build_selection_streams(cls, inst): # Colors stream colors_stream = _Colors( colors=[inst.unselected_color, inst.selected_color]) # Cmap streams cmap_streams = [ _Cmap(cmap=inst.unselected_cmap), _Cmap(cmap=inst.selected_cmap), ] def update_colors(*_): colors_stream.event( colors=[inst.unselected_color, inst.selected_color]) cmap_streams[0].event(cmap=inst.unselected_cmap) cmap_streams[1].event(cmap=inst.selected_cmap) inst.param.watch( update_colors, parameter_names=['unselected_color', 'selected_color']) # Exprs stream exprs_stream = _Exprs(exprs=[True, None]) def update_exprs(*_): exprs_stream.event(exprs=[True, inst.selection_expr]) inst.param.watch(update_exprs, parameter_names=['selection_expr']) # Alpha streams alpha_streams = [ _Alpha(alpha=255), _Alpha(alpha=inst._selected_alpha), ] def update_alphas(*_): alpha_streams[1].event(alpha=inst._selected_alpha) inst.param.watch(update_alphas, parameter_names=['selection_expr']) return _SelectionStreams( colors_stream=colors_stream, exprs_stream=exprs_stream, alpha_streams=alpha_streams, cmap_streams=cmap_streams, ) @property def unselected_cmap(self): """ The datashader colormap for unselected data """ return _color_to_cmap(self.unselected_color) @property def selected_cmap(self): """ The datashader colormap for selected data """ return _color_to_cmap(self.selected_color) @property def _selected_alpha(self): if self.selection_expr: return 255 else: return 0 def _expr_stream_updated(self, hvobj, selection_expr, bbox): if selection_expr: self.selection_expr = selection_expr
class _config(_base_config): """ Holds global configuration options for Panel. The options can be set directly on the global config instance, via keyword arguments in the extension or via environment variables. For example to set the embed option the following approaches can be used: pn.config.embed = True pn.extension(embed=True) os.environ['PANEL_EMBED'] = 'True' """ apply_signatures = param.Boolean(default=True, doc=""" Whether to set custom Signature which allows tab-completion in some IDEs and environments.""") autoreload = param.Boolean(default=False, doc=""" Whether to autoreload server when script changes.""") loading_spinner = param.Selector( default='arcs', objects=['arc', 'arcs', 'bar', 'dots', 'petal'], doc=""" Loading indicator to use when component loading parameter is set.""") loading_color = param.Color(default='#c3c3c3', doc=""" Color of the loading indicator.""") loading_max_height = param.Integer(default=400, doc=""" Maximum height of the loading indicator.""") notifications = param.Boolean(default=False, doc=""" Whether to enable notifications functionality.""") profiler = param.Selector(default=None, allow_None=True, objects=['pyinstrument', 'snakeviz'], doc=""" The profiler engine to enable.""") safe_embed = param.Boolean(default=False, doc=""" Ensure all bokeh property changes trigger events which are embedded. Useful when only partial updates are made in an app, e.g. when working with HoloViews.""") session_history = param.Integer(default=0, bounds=(-1, None), doc=""" If set to a non-negative value this determines the maximum length of the pn.state.session_info dictionary, which tracks information about user sessions. A value of -1 indicates an unlimited history.""") sizing_mode = param.ObjectSelector(default=None, objects=[ 'fixed', 'stretch_width', 'stretch_height', 'stretch_both', 'scale_width', 'scale_height', 'scale_both', None ], doc=""" Specify the default sizing mode behavior of panels.""") template = param.ObjectSelector(default=None, doc=""" The default template to render served applications into.""") theme = param.ObjectSelector(default='default', objects=['default', 'dark'], doc=""" The theme to apply to the selected global template.""") throttled = param.Boolean(default=False, doc=""" If sliders and inputs should be throttled until release of mouse.""") _admin = param.Boolean(default=False, doc="Whether the admin panel was enabled.") _comms = param.ObjectSelector( default='default', objects=['default', 'ipywidgets', 'vscode', 'colab'], doc=""" Whether to render output in Jupyter with the default Jupyter extension or use the jupyter_bokeh ipywidget model.""") _console_output = param.ObjectSelector( default='accumulate', allow_None=True, objects=['accumulate', 'replace', 'disable', False], doc=""" How to log errors and stdout output triggered by callbacks from Javascript in the notebook.""") _cookie_secret = param.String(default=None, doc=""" Configure to enable getting/setting secure cookies.""") _embed = param.Boolean(default=False, allow_None=True, doc=""" Whether plot data will be embedded.""") _embed_json = param.Boolean(default=False, doc=""" Whether to save embedded state to json files.""") _embed_json_prefix = param.String(default='', doc=""" Prefix for randomly generated json directories.""") _embed_load_path = param.String(default=None, doc=""" Where to load json files for embedded state.""") _embed_save_path = param.String(default='./', doc=""" Where to save json files for embedded state.""") _log_level = param.Selector( default='WARNING', objects=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], doc="Log level of Panel loggers") _nthreads = param.Integer(default=None, doc=""" When set to a non-None value a thread pool will be started. Whenever an event arrives from the frontend it will be dispatched to the thread pool to be processed.""") _oauth_provider = param.ObjectSelector(default=None, allow_None=True, objects=[], doc=""" Select between a list of authentification providers.""") _oauth_expiry = param.Number(default=1, bounds=(0, None), doc=""" Expiry of the OAuth cookie in number of days.""") _oauth_key = param.String(default=None, doc=""" A client key to provide to the OAuth provider.""") _oauth_secret = param.String(default=None, doc=""" A client secret to provide to the OAuth provider.""") _oauth_jwt_user = param.String(default=None, doc=""" The key in the ID JWT token to consider the user.""") _oauth_redirect_uri = param.String(default=None, doc=""" A redirect URI to provide to the OAuth provider.""") _oauth_encryption_key = param.ClassSelector(default=None, class_=bytes, doc=""" A random string used to encode OAuth related user information.""") _oauth_extra_params = param.Dict(default={}, doc=""" Additional parameters required for OAuth provider.""") _inline = param.Boolean(default=_LOCAL_DEV_VERSION, allow_None=True, doc=""" Whether to inline JS and CSS resources. If disabled, resources are loaded from CDN if one is available.""") _globals = [ 'autoreload', 'comms', 'cookie_secret', 'nthreads', 'oauth_provider', 'oauth_expiry', 'oauth_key', 'oauth_secret', 'oauth_jwt_user', 'oauth_redirect_uri', 'oauth_encryption_key', 'oauth_extra_params' ] _truthy = ['True', 'true', '1', True, 1] _session_config = WeakKeyDictionary() def __init__(self, **params): super().__init__(**params) self._validating = False for p in self.param: if p.startswith('_') and p[1:] not in self._globals: setattr(self, p + '_', None) if self.log_level: panel_log_handler.setLevel(self.log_level) @param.depends('_nthreads', watch=True, on_init=True) def _set_thread_pool(self): from .io.state import state if self.nthreads is None: if state._thread_pool is not None: state._thread_pool.shutdown(wait=False) state._thread_pool = None return if state._thread_pool: raise RuntimeError("Thread pool already running") threads = self.nthreads if self.nthreads else None state._thread_pool = ThreadPoolExecutor(max_workers=threads) @param.depends('notifications', watch=True) def _enable_notifications(self): from .io.notifications import NotificationArea from .io.state import state if not state.curdoc: state._notification = NotificationArea() @contextmanager def set(self, **kwargs): values = [(k, v) for k, v in self.param.values().items() if k != 'name'] overrides = [(k, getattr(self, k + '_')) for k in self.param if k.startswith('_') and k[1:] not in self._globals] for k, v in kwargs.items(): setattr(self, k, v) try: yield finally: self.param.update(**dict(values)) for k, v in overrides: setattr(self, k + '_', v) def __setattr__(self, attr, value): from .io.state import state if not getattr(self, 'initialized', False) or ( attr.startswith('_') and attr.endswith('_')) or attr == '_validating': return super().__setattr__(attr, value) value = getattr(self, f'_{attr}_hook', lambda x: x)(value) if attr in self._globals: super().__setattr__(attr if attr in self.param else f'_{attr}', value) elif state.curdoc is not None: if attr in self.param: validate_config(self, attr, value) elif f'_{attr}' in self.param: validate_config(self, f'_{attr}', value) else: raise AttributeError( f'{attr!r} is not a valid config parameter.') if state.curdoc not in self._session_config: self._session_config[state.curdoc] = {} self._session_config[state.curdoc][attr] = value elif f'_{attr}' in self.param and hasattr(self, f'_{attr}_'): validate_config(self, f'_{attr}', value) super().__setattr__(f'_{attr}_', value) else: super().__setattr__(attr, value) @param.depends('_log_level', watch=True) def _update_log_level(self): panel_log_handler.setLevel(self._log_level) def __getattribute__(self, attr): from .io.state import state init = super().__getattribute__('initialized') global_params = super().__getattribute__('_globals') if init and not attr.startswith('__'): params = super().__getattribute__('param') else: params = [] session_config = super().__getattribute__('_session_config') if state.curdoc and state.curdoc not in session_config: session_config[state.curdoc] = {} if (attr in ('raw_css', 'css_files', 'js_files', 'js_modules') and state.curdoc and attr not in session_config[state.curdoc]): new_obj = copy.copy(super().__getattribute__(attr)) setattr(self, attr, new_obj) if attr in global_params: return super().__getattribute__(attr) elif state.curdoc and state.curdoc in session_config and attr in session_config[ state.curdoc]: return session_config[state.curdoc][attr] elif f'_{attr}' in params and getattr(self, f'_{attr}_') is not None: return super().__getattribute__(f'_{attr}_') return super().__getattribute__(attr) def _console_output_hook(self, value): return value if value else 'disable' def _template_hook(self, value): if isinstance(value, str): return self.param.template.names[value] return value @property def _doc_build(self): return os.environ.get('PANEL_DOC_BUILD') @property def console_output(self): if self._doc_build: return 'disable' else: return os.environ.get('PANEL_CONSOLE_OUTPUT', _config._console_output) @property def embed(self): return os.environ.get('PANEL_EMBED', _config._embed) in self._truthy @property def comms(self): return os.environ.get('PANEL_COMMS', self._comms) @property def embed_json(self): return os.environ.get('PANEL_EMBED_JSON', _config._embed_json) in self._truthy @property def embed_json_prefix(self): return os.environ.get('PANEL_EMBED_JSON_PREFIX', _config._embed_json_prefix) @property def embed_save_path(self): return os.environ.get('PANEL_EMBED_SAVE_PATH', _config._embed_save_path) @property def embed_load_path(self): return os.environ.get('PANEL_EMBED_LOAD_PATH', _config._embed_load_path) @property def inline(self): return os.environ.get('PANEL_INLINE', _config._inline) in self._truthy @property def log_level(self): log_level = os.environ.get('PANEL_LOG_LEVEL', self._log_level) return log_level.upper() if log_level else None @property def nthreads(self): nthreads = os.environ.get('PANEL_NUM_THREADS', self._nthreads) return None if nthreads is None else int(nthreads) @property def oauth_provider(self): provider = os.environ.get('PANEL_OAUTH_PROVIDER', self._oauth_provider) return provider.lower() if provider else None @property def oauth_expiry(self): provider = os.environ.get('PANEL_OAUTH_EXPIRY', self._oauth_expiry) return float(provider) @property def oauth_key(self): return os.environ.get('PANEL_OAUTH_KEY', self._oauth_key) @property def cookie_secret(self): return os.environ.get( 'PANEL_COOKIE_SECRET', os.environ.get('BOKEH_COOKIE_SECRET', self._cookie_secret)) @property def oauth_secret(self): return os.environ.get('PANEL_OAUTH_SECRET', self._oauth_secret) @property def oauth_redirect_uri(self): return os.environ.get('PANEL_OAUTH_REDIRECT_URI', self._oauth_redirect_uri) @property def oauth_jwt_user(self): return os.environ.get('PANEL_OAUTH_JWT_USER', self._oauth_jwt_user) @property def oauth_encryption_key(self): return os.environ.get('PANEL_OAUTH_ENCRYPTION', self._oauth_encryption_key) @property def oauth_extra_params(self): if 'PANEL_OAUTH_EXTRA_PARAMS' in os.environ: return ast.literal_eval(os.environ['PANEL_OAUTH_EXTRA_PARAMS']) else: return self._oauth_extra_params
class DataSource(param.Parameterized): tags = param.List( doc='List of tags to specify the type of data in the dataobject.') source = param.ClassSelector( ColumnDataSource, doc='ColumnDataSource object which is used for graphical display') renderer = param.String(default='line') default_color = param.Color( default='#0611d4') # todo get default color from css? def __init__(self, input_data, **params): #update to lumen / pandas dataframes self.render_kwargs = { k: params.pop(k) for k in list(params.keys()) if k not in self.param } #todo currently this override colors in dic super(DataSource, self).__init__(**params) dic = self.get_dic(input_data) default_color = 'color' if 'color' in dic else self.default_color self.render_kwargs['color'] = self.render_kwargs.get( 'color', default_color) self.source = ColumnDataSource(dic, name=self.name) def __getitem__(self, item): return self.source.data.__getitem__(item) @property #cached property? def df(self): df = pd.DataFrame(self.source.data) return df @property def export_df(self): df = pd.DataFrame({ k: v for k, v in self.source.data.items() if not k.startswith('__') }) return df def get_dic(self, input_data): #todo allow dataframes if isinstance(input_data, np.ndarray): dic = {name: input_data[name] for name in input_data.dtype.names} #self.array = input_data # elif isinstance(input_data, dict): if 'image' in self.tags: # Images requires lists of arrays rather than arrays dic = {k: v for k, v in input_data.items()} else: dic = {k: np.array(v) for k, v in input_data.items()} elif isinstance(input_data, Protein): dic = { k: np.array(v) for k, v in input_data.to_dict('list').items() } dic['r_number'] = np.array(input_data.index) else: raise TypeError("Invalid input data type") #todo this does not apply to all data sets? (it does not, for example images) if 'color' not in dic.keys() and 'image' not in self.tags: column = next(iter(dic.values())) color = np.full_like(column, fill_value=self.default_color, dtype='<U7') dic['color'] = color return dic def to_numpy(self): raise NotImplementedError( 'Converting to numpy rec array not implemented') @property def scalar_fields(self): """Returns a list of names of fields with scalar dtype""" return [ name for name, data in self.source.data.items() if np.issubdtype(data.dtype, np.number) ] @property def y(self): """:class:`~numpy.ndarray`: Array of y values""" if 'y' in self.render_kwargs: try: return self.source.data[self.render_kwargs['y']] except TypeError: return None # 'y' might be a list of y values elif 'y' in self.source.data: return self.source.data['y'] else: return None @property def x(self): """:class:`~numpy.ndarray`: Array of x values""" if 'x' in self.render_kwargs: return self.source.data[self.render_kwargs['x']] elif 'x' in self.source.data: return self.source.data['x'] else: return None def update(self, data_source_obj): """ Update the data and source object Parameters ---------- data_source Returns ------- """ self.source.data.update(**data_source_obj.source.data) def resolve_tags(self, tags): # format ['tag1', ('tag2a', 'tag2b') ] = tag1 OR (tag2a AND tag2b) for tag in tags: if isinstance(tag, str): bool = tag in self.tags # if tag in self.tags: # return True else: bool = all(sub_tag in self.tags for sub_tag in tag) if bool: return True return False
class link_selections(_base_link_selections): """ Operation which automatically links selections between elements in the supplied HoloViews object. Can be used a single time or be used as an instance to apply the linked selections across multiple objects. """ cross_filter_mode = param.Selector(['overwrite', 'intersect'], default='intersect', doc=""" Determines how to combine selections across different elements.""") index_cols = param.List(default=None, doc=""" If provided, selection switches to index mode where all queries are expressed solely in terms of discrete values along the index_cols. All Elements given to link_selections must define the index_cols, either as explicit dimensions or by sharing an underlying Dataset that defines them.""" ) selection_expr = param.Parameter(default=None, doc=""" dim expression of the current selection or None to indicate that everything is selected.""") selected_color = param.Color(default=None, allow_None=True, doc=""" Color of selected data, or None to use the original color of each element.""") selection_mode = param.Selector( ['overwrite', 'intersect', 'union', 'inverse'], default='overwrite', doc=""" Determines how to combine successive selections on the same element.""") show_regions = param.Boolean(default=True, doc=""" Whether to highlight the selected regions.""") unselected_alpha = param.Magnitude(default=0.1, doc=""" Alpha of unselected data.""") unselected_color = param.Color(default=None, doc=""" Color of unselected data.""") @bothmethod def instance(self_or_cls, **params): inst = super(link_selections, self_or_cls).instance(**params) # Initialize private properties inst._obj_selections = {} inst._obj_regions = {} inst._reset_regions = True return inst @classmethod def _build_selection_streams(cls, inst): # Colors stream style_stream = _Styles( colors=[inst.unselected_color, inst.selected_color], alpha=inst.unselected_alpha) # Cmap streams cmap_streams = [ _Cmap(cmap=inst.unselected_cmap), _Cmap(cmap=inst.selected_cmap), ] def update_colors(*_): colors = [inst.unselected_color, inst.selected_color] style_stream.event(colors=colors, alpha=inst.unselected_alpha) cmap_streams[0].event(cmap=inst.unselected_cmap) if cmap_streams[1] is not None: cmap_streams[1].event(cmap=inst.selected_cmap) inst.param.watch( update_colors, ['unselected_color', 'selected_color', 'unselected_alpha']) # Exprs stream exprs_stream = _Exprs(exprs=[True, None]) def update_exprs(*_): exprs_stream.event(exprs=[True, inst.selection_expr]) # Reset regions if inst._reset_regions: for k, v in inst._region_streams.items(): inst._region_streams[k].event(region_element=None) inst._obj_selections.clear() inst._obj_regions.clear() inst.param.watch(update_exprs, ['selection_expr']) return _SelectionStreams( style_stream=style_stream, exprs_stream=exprs_stream, cmap_streams=cmap_streams, ) @property def unselected_cmap(self): """ The datashader colormap for unselected data """ if self.unselected_color is None: return None return _color_to_cmap(self.unselected_color) @property def selected_cmap(self): """ The datashader colormap for selected data """ return None if self.selected_color is None else _color_to_cmap( self.selected_color) def _expr_stream_updated(self, hvobj, selection_expr, bbox, region_element, **kwargs): if selection_expr: if self.cross_filter_mode == "overwrite": # clear other regions and selections for k, v in self._region_streams.items(): if k is not hvobj: self._region_streams[k].event(region_element=None) self._obj_regions.pop(k, None) self._obj_selections.pop(k, None) # Update selection expression if hvobj not in self._obj_selections or self.selection_mode == "overwrite": if self.selection_mode == "inverse": self._obj_selections[hvobj] = ~selection_expr else: self._obj_selections[hvobj] = selection_expr else: if self.selection_mode == "intersect": self._obj_selections[hvobj] &= selection_expr elif self.selection_mode == "union": self._obj_selections[hvobj] |= selection_expr else: # inverse self._obj_selections[hvobj] &= ~selection_expr # Update region if self.show_regions: if isinstance(hvobj, DynamicMap): el_type = hvobj.type else: el_type = hvobj region_element = el_type._merge_regions( self._obj_regions.get(hvobj, None), region_element, self.selection_mode) self._obj_regions[hvobj] = region_element else: region_element = None # build combined selection selection_exprs = list(self._obj_selections.values()) if self.index_cols: if len(selection_exprs) > 1: vals = set.intersection(*(set(expr.ops[2]['args'][0]) for expr in selection_exprs)) old = selection_exprs[0] selection_expr = dim('new') selection_expr.dimension = old.dimension selection_expr.ops = list(old.ops) selection_expr.ops[2] = dict(selection_expr.ops[2], args=(list(vals), )) else: selection_expr = selection_exprs[0] for expr in selection_exprs[1:]: selection_expr = selection_expr & expr # Set _reset_regions to False so that plot regions aren't automatically # cleared when self.selection_expr is set. self._reset_regions = False self.selection_expr = selection_expr self._reset_regions = True # update this region stream if self._region_streams.get(hvobj, None) is not None: self._region_streams[hvobj].event( region_element=region_element)
class _config(_base_config): """ Holds global configuration options for Panel. The options can be set directly on the global config instance, via keyword arguments in the extension or via environment variables. For example to set the embed option the following approaches can be used: pn.config.embed = True pn.extension(embed=True) os.environ['PANEL_EMBED'] = 'True' """ apply_signatures = param.Boolean(default=True, doc=""" Whether to set custom Signature which allows tab-completion in some IDEs and environments.""") autoreload = param.Boolean(default=False, doc=""" Whether to autoreload server when script changes.""") loading_spinner = param.Selector( default='arcs', objects=['arc', 'arcs', 'bar', 'dots', 'petal'], doc=""" Loading indicator to use when component loading parameter is set.""") loading_color = param.Color(default='#c3c3c3', doc=""" Color of the loading indicator.""") safe_embed = param.Boolean(default=False, doc=""" Ensure all bokeh property changes trigger events which are embedded. Useful when only partial updates are made in an app, e.g. when working with HoloViews.""") session_history = param.Integer(default=0, bounds=(-1, None), doc=""" If set to a non-negative value this determines the maximum length of the pn.state.session_info dictionary, which tracks information about user sessions. A value of -1 indicates an unlimited history.""") sizing_mode = param.ObjectSelector(default=None, objects=[ 'fixed', 'stretch_width', 'stretch_height', 'stretch_both', 'scale_width', 'scale_height', 'scale_both', None ], doc=""" Specify the default sizing mode behavior of panels.""") throttled = param.Boolean(default=False, doc=""" If sliders and inputs should be throttled until release of mouse.""") _comms = param.ObjectSelector( default='default', objects=['default', 'ipywidgets', 'vscode', 'colab'], doc=""" Whether to render output in Jupyter with the default Jupyter extension or use the jupyter_bokeh ipywidget model.""") _console_output = param.ObjectSelector( default='accumulate', allow_None=True, objects=['accumulate', 'replace', 'disable', False], doc=""" How to log errors and stdout output triggered by callbacks from Javascript in the notebook.""") _cookie_secret = param.String(default=None, doc=""" Configure to enable getting/setting secure cookies.""") _embed = param.Boolean(default=False, allow_None=True, doc=""" Whether plot data will be embedded.""") _embed_json = param.Boolean(default=False, doc=""" Whether to save embedded state to json files.""") _embed_json_prefix = param.String(default='', doc=""" Prefix for randomly generated json directories.""") _embed_load_path = param.String(default=None, doc=""" Where to load json files for embedded state.""") _embed_save_path = param.String(default='./', doc=""" Where to save json files for embedded state.""") _log_level = param.Selector( default=None, objects=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], doc="Log level of Panel loggers") _oauth_provider = param.ObjectSelector(default=None, allow_None=True, objects=[], doc=""" Select between a list of authentification providers.""") _oauth_key = param.String(default=None, doc=""" A client key to provide to the OAuth provider.""") _oauth_secret = param.String(default=None, doc=""" A client secret to provide to the OAuth provider.""") _oauth_jwt_user = param.String(default=None, doc=""" The key in the ID JWT token to consider the user.""") _oauth_redirect_uri = param.String(default=None, doc=""" A redirect URI to provide to the OAuth provider.""") _oauth_encryption_key = param.ClassSelector(default=None, class_=bytes, doc=""" A random string used to encode OAuth related user information.""") _oauth_extra_params = param.Dict(default={}, doc=""" Additional parameters required for OAuth provider.""") _inline = param.Boolean(default=_LOCAL_DEV_VERSION, allow_None=True, doc=""" Whether to inline JS and CSS resources. If disabled, resources are loaded from CDN if one is available.""") _truthy = ['True', 'true', '1', True, 1] def __init__(self, **params): super().__init__(**params) for p in self.param: if p.startswith('_'): setattr(self, p + '_', None) @contextmanager def set(self, **kwargs): values = [(k, v) for k, v in self.param.get_param_values() if k != 'name'] overrides = [(k, getattr(self, k + '_')) for k in self.param if k.startswith('_')] for k, v in kwargs.items(): setattr(self, k, v) try: yield finally: self.param.set_param(**dict(values)) for k, v in overrides: setattr(self, k + '_', v) @property def _doc_build(self): return os.environ.get('PANEL_DOC_BUILD') @property def console_output(self): if self._console_output_ is not None: return 'disable' if not self._console_output_ else self._console_output_ elif self._doc_build: return 'disable' else: return os.environ.get('PANEL_CONSOLE_OUTPUT', _config._console_output) @console_output.setter def console_output(self, value): validate_config(self, '_console_output', value) self._console_output_ = value @property def embed(self): if self._embed_ is not None: return self._embed_ else: return os.environ.get('PANEL_EMBED', _config._embed) in self._truthy @embed.setter def embed(self, value): validate_config(self, '_embed', value) self._embed_ = value @property def comms(self): if self._comms_ is not None: return self._comms_ else: return os.environ.get('PANEL_COMMS', _config._comms) @comms.setter def comms(self, value): validate_config(self, '_comms', value) self._comms_ = value @property def embed_json(self): if self._embed_json_ is not None: return self._embed_json_ else: return os.environ.get('PANEL_EMBED_JSON', _config._embed_json) in self._truthy @embed_json.setter def embed_json(self, value): validate_config(self, '_embed_json', value) self._embed_json_ = value @property def embed_json_prefix(self): if self._embed_json_prefix_ is not None: return self._embed_json_prefix_ else: return os.environ.get('PANEL_EMBED_JSON_PREFIX', _config._embed_json_prefix) @embed_json_prefix.setter def embed_json_prefix(self, value): validate_config(self, '_embed_json_prefix', value) self._embed_json_prefix_ = value @property def embed_save_path(self): if self._embed_save_path_ is not None: return self._embed_save_path_ else: return os.environ.get('PANEL_EMBED_SAVE_PATH', _config._embed_save_path) @embed_save_path.setter def embed_save_path(self, value): validate_config(self, '_embed_save_path', value) self._embed_save_path_ = value @property def embed_load_path(self): if self._embed_load_path_ is not None: return self._embed_load_path_ else: return os.environ.get('PANEL_EMBED_LOAD_PATH', _config._embed_load_path) @embed_load_path.setter def embed_load_path(self, value): validate_config(self, '_embed_load_path', value) self._embed_load_path_ = value @property def inline(self): if self._inline_ is not None: return self._inline_ else: return os.environ.get('PANEL_INLINE', _config._inline) in self._truthy @inline.setter def inline(self, value): validate_config(self, '_inline', value) self._inline_ = value @property def log_level(self): if self._log_level_ is not None: return self._log_level_ elif 'PANEL_LOG_LEVEL' in os.environ: return os.environ['PANEL_LOG_LEVEL'].upper() else: return self._log_level @log_level.setter def log_level(self, value): validate_config(self, '_log_level', value) self._log_level_ = value @property def oauth_provider(self): if self._oauth_provider_ is not None: return self._oauth_provider_ else: provider = os.environ.get('PANEL_OAUTH_PROVIDER', _config._oauth_provider) return provider.lower() if provider else None @oauth_provider.setter def oauth_provider(self, value): validate_config(self, '_oauth_provider', value.lower()) self._oauth_provider_ = value.lower() @property def oauth_key(self): if self._oauth_key_ is not None: return self._oauth_key_ else: return os.environ.get('PANEL_OAUTH_KEY', _config._oauth_key) @oauth_key.setter def oauth_key(self, value): validate_config(self, '_oauth_key', value) self._oauth_key_ = value @property def cookie_secret(self): if self._cookie_secret_ is not None: return self._cookie_secret_ else: return os.environ.get( 'PANEL_COOKIE_SECRET', os.environ.get('BOKEH_COOKIE_SECRET', _config._cookie_secret)) @cookie_secret.setter def cookie_secret(self, value): validate_config(self, '_cookie_secret', value) self._cookie_secret_ = value @property def oauth_secret(self): if self._oauth_secret_ is not None: return self._oauth_secret_ else: return os.environ.get('PANEL_OAUTH_SECRET', _config._oauth_secret) @oauth_secret.setter def oauth_secret(self, value): validate_config(self, '_oauth_secret', value) self._oauth_secret_ = value @property def oauth_redirect_uri(self): if self._oauth_redirect_uri_ is not None: return self._oauth_redirect_uri_ else: return os.environ.get('PANEL_OAUTH_REDIRECT_URI', _config._oauth_redirect_uri) @oauth_redirect_uri.setter def oauth_redirect_uri(self, value): validate_config(self, '_oauth_redirect_uri', value) self._oauth_redirect_uri_ = value @property def oauth_jwt_user(self): if self._oauth_jwt_user_ is not None: return self._oauth_jwt_user_ else: return os.environ.get('PANEL_OAUTH_JWT_USER', _config._oauth_jwt_user) @oauth_jwt_user.setter def oauth_jwt_user(self, value): validate_config(self, '_oauth_jwt_user', value) self._oauth_jwt_user_ = value @property def oauth_encryption_key(self): if self._oauth_encryption_key_ is not None: return self._oauth_encryption_key_ else: return os.environ.get('PANEL_OAUTH_ENCRYPTION', _config._oauth_encryption_key) @oauth_encryption_key.setter def oauth_encryption_key(self, value): validate_config(self, '_oauth_encryption_key', value) self._oauth_encryption_key_ = value @property def oauth_extra_params(self): if self._oauth_extra_params_ is not None: return self._oauth_extra_params_ else: if 'PANEL_OAUTH_EXTRA_PARAMS' in os.environ: return ast.literal_eval(os.environ['PANEL_OAUTH_EXTRA_PARAMS']) else: return _config._oauth_extra_params @oauth_extra_params.setter def oauth_extra_params(self, value): validate_config(self, '_oauth_extra_params', value) self._oauth_extra_params_ = value
class VTKVolume(AbstractVTK): """ The `VTKVolume` pane renders 3d volumetric data defined on regular grids. It may be constructed from a 3D NumPy array or a vtkVolume. The pane provides a number of interactive control which can be set either through callbacks from Python or Javascript callbacks. Reference: https://panel.holoviz.org/reference/panes/VTKVolume.html :Example: >>> pn.extension('vtk') >>> VTKVolume( ... data_matrix, spacing=(3,2,1), interpolation='nearest', ... edge_gradient=0, sampling=0, ... sizing_mode='stretch_width', height=400, ... ) """ ambient = param.Number(default=0.2, step=1e-2, doc=""" Value to control the ambient lighting. It is the light an object gives even in the absence of strong light. It is constant in all directions.""") controller_expanded = param.Boolean(default=True, doc=""" If True the volume controller panel options is expanded in the view""") colormap = param.Selector(default='erdc_rainbow_bright', objects=PRESET_CMAPS, doc=""" Name of the colormap used to transform pixel value in color.""") diffuse = param.Number(default=0.7, step=1e-2, doc=""" Value to control the diffuse Lighting. It relies on both the light direction and the object surface normal.""") display_volume = param.Boolean(default=True, doc=""" If set to True, the 3D respresentation of the volume is displayed using ray casting.""") display_slices = param.Boolean(default=False, doc=""" If set to true, the orthgonal slices in the three (X, Y, Z) directions are displayed. Position of each slice can be controlled using slice_(i,j,k) parameters.""") edge_gradient = param.Number(default=0.4, bounds=(0, 1), step=1e-2, doc=""" Parameter to adjust the opacity of the volume based on the gradient between voxels.""") interpolation = param.Selector( default='fast_linear', objects=['fast_linear', 'linear', 'nearest'], doc=""" interpolation type for sampling a volume. `nearest` interpolation will snap to the closest voxel, `linear` will perform trilinear interpolation to compute a scalar value from surrounding voxels. `fast_linear` under WebGL 1 will perform bilinear interpolation on X and Y but use nearest for Z. This is slightly faster than full linear at the cost of no Z axis linear interpolation.""") mapper = param.Dict(doc="Lookup Table in format {low, high, palette}") max_data_size = param.Number(default=(256**3) * 2 / 1e6, doc=""" Maximum data size transfert allowed without subsampling""") nan_opacity = param.Number(default=1., bounds=(0., 1.), doc=""" Opacity applied to nan values in slices""") origin = param.Tuple(default=None, length=3, allow_None=True) render_background = param.Color(default='#52576e', doc=""" Allows to specify the background color of the 3D rendering. The value must be specified as an hexadecimal color string.""") rescale = param.Boolean(default=False, doc=""" If set to True the colormap is rescaled beween min and max value of the non-transparent pixel, otherwise the full range of the pixel values are used.""") shadow = param.Boolean(default=True, doc=""" If set to False, then the mapper for the volume will not perform shading computations, it is the same as setting ambient=1, diffuse=0, specular=0.""") sampling = param.Number(default=0.4, bounds=(0, 1), step=1e-2, doc=""" Parameter to adjust the distance between samples used for rendering. The lower the value is the more precise is the representation but it is more computationally intensive.""") spacing = param.Tuple(default=(1, 1, 1), length=3, doc=""" Distance between voxel in each direction""") specular = param.Number(default=0.3, step=1e-2, doc=""" Value to control specular lighting. It is the light reflects back toward the camera when hitting the object.""") specular_power = param.Number(default=8., doc=""" Specular power refers to how much light is reflected in a mirror like fashion, rather than scattered randomly in a diffuse manner.""") slice_i = param.Integer(per_instance=True, doc=""" Integer parameter to control the position of the slice normal to the X direction.""") slice_j = param.Integer(per_instance=True, doc=""" Integer parameter to control the position of the slice normal to the Y direction.""") slice_k = param.Integer(per_instance=True, doc=""" Integer parameter to control the position of the slice normal to the Z direction.""") _serializers = {} _rename = {'max_data_size': None, 'spacing': None, 'origin': None} _updates = True def __init__(self, object=None, **params): super().__init__(object, **params) self._sub_spacing = self.spacing self._update() @classmethod def applies(cls, obj): if ((isinstance(obj, np.ndarray) and obj.ndim == 3) or any([isinstance(obj, k) for k in cls._serializers.keys()])): return True elif 'vtk' not in sys.modules and 'vtkmodules' not in sys.modules: return False else: import vtk return isinstance(obj, vtk.vtkImageData) def _get_model(self, doc, root=None, parent=None, comm=None): VTKVolumePlot = lazy_load('panel.models.vtk', 'VTKVolumePlot', isinstance(comm, JupyterComm), root) props = self._process_param_change(self._init_params()) if self._volume_data is not None: props['data'] = self._volume_data model = VTKVolumePlot(**props) if root is None: root = model self._link_props(model, [ 'colormap', 'orientation_widget', 'camera', 'mapper', 'controller_expanded', 'nan_opacity' ], doc, root, comm) self._models[root.ref['id']] = (model, parent) return model def _update_object(self, ref, doc, root, parent, comm): self._legend = None super()._update_object(ref, doc, root, parent, comm) def _get_object_dimensions(self): if isinstance(self.object, np.ndarray): return self.object.shape else: return self.object.GetDimensions() def _process_param_change(self, msg): msg = super()._process_param_change(msg) if self.object is not None: slice_params = {'slice_i': 0, 'slice_j': 1, 'slice_k': 2} for k, v in msg.items(): sub_dim = self._subsample_dimensions ori_dim = self._orginal_dimensions if k in slice_params: index = slice_params[k] msg[k] = int(np.round(v * sub_dim[index] / ori_dim[index])) return msg def _process_property_change(self, msg): msg = super()._process_property_change(msg) if self.object is not None: slice_params = {'slice_i': 0, 'slice_j': 1, 'slice_k': 2} for k, v in msg.items(): sub_dim = self._subsample_dimensions ori_dim = self._orginal_dimensions if k in slice_params: index = slice_params[k] msg[k] = int(np.round(v * ori_dim[index] / sub_dim[index])) return msg def _update(self, ref=None, model=None): self._volume_data = self._get_volume_data() if self._volume_data is not None: self._orginal_dimensions = self._get_object_dimensions() self._subsample_dimensions = self._volume_data['dims'] self.param.slice_i.bounds = (0, self._orginal_dimensions[0] - 1) self.slice_i = (self._orginal_dimensions[0] - 1) // 2 self.param.slice_j.bounds = (0, self._orginal_dimensions[1] - 1) self.slice_j = (self._orginal_dimensions[1] - 1) // 2 self.param.slice_k.bounds = (0, self._orginal_dimensions[2] - 1) self.slice_k = (self._orginal_dimensions[2] - 1) // 2 if model is not None: model.data = self._volume_data @classmethod def register_serializer(cls, class_type, serializer): """ Register a seriliazer for a given type of class. A serializer is a function which take an instance of `class_type` (like a vtk.vtkImageData) as input and return a numpy array of the data """ cls._serializers.update({class_type: serializer}) def _volume_from_array(self, sub_array): return dict(buffer=base64encode(sub_array.ravel(order='F')), dims=sub_array.shape, spacing=self._sub_spacing, origin=self.origin, data_range=(np.nanmin(sub_array), np.nanmax(sub_array)), dtype=sub_array.dtype.name) def _get_volume_data(self): if self.object is None: return None elif isinstance(self.object, np.ndarray): return self._volume_from_array(self._subsample_array(self.object)) else: available_serializer = [ v for k, v in VTKVolume._serializers.items() if isinstance(self.object, k) ] if not available_serializer: import vtk from vtk.util import numpy_support def volume_serializer(inst): imageData = inst.object array = numpy_support.vtk_to_numpy( imageData.GetPointData().GetScalars()) dims = imageData.GetDimensions() inst.spacing = imageData.GetSpacing() inst.origin = imageData.GetOrigin() return inst._volume_from_array( inst._subsample_array(array.reshape(dims, order='F'))) VTKVolume.register_serializer(vtk.vtkImageData, volume_serializer) serializer = volume_serializer else: serializer = available_serializer[0] return serializer(self) def _subsample_array(self, array): original_shape = array.shape spacing = self.spacing extent = tuple( (o_s - 1) * s for o_s, s in zip(original_shape, spacing)) dim_ratio = np.cbrt((array.nbytes / 1e6) / self.max_data_size) max_shape = tuple(int(o_s / dim_ratio) for o_s in original_shape) dowsnscale_factor = [ max(o_s, m_s) / m_s for m_s, o_s in zip(max_shape, original_shape) ] if any([d_f > 1 for d_f in dowsnscale_factor]): try: import scipy.ndimage as nd sub_array = nd.interpolation.zoom( array, zoom=[1 / d_f for d_f in dowsnscale_factor], order=0, mode="nearest") except ImportError: sub_array = array[::int(np.ceil(dowsnscale_factor[0])), ::int( np.ceil(dowsnscale_factor[1]) ), ::int(np.ceil(dowsnscale_factor[2]))] self._sub_spacing = tuple(e / (s - 1) for e, s in zip(extent, sub_array.shape)) else: sub_array = array self._sub_spacing = self.spacing return sub_array
class ArcProgressIndicator(pn.reactive.ReactiveHTML): progress = param.Number(default=0, bounds=(0, 100)) transition_duration = param.Number(default=0.5, bounds=(0, None)) format_options = param.Dict( default={ "locale": "en-US", "style": "percent", "minimumIntegerDigits": "1", "maximumIntegerDigits": "3", "minimumFractionDigits": "1", "maximumFractionDigits": "1" }) text_style = param.Dict(default={ "font-size": 4.5, "text-anchor": "middle", "letter-spacing": -0.2, }) empty_color = param.Color(default="#e8f6fd") fill_color = param.Color(default="#2a87d8") use_gradient = param.Boolean(default=False) gradient = param.Parameter(default=[{ "stop": 0, "color": "green" }, { "stop": 1, "color": "red" }]) annotations = param.Parameter(default=[]) viewbox = param.List(default=[0, -1, 20, 10], constant=True) _template = """ <div id="arcprog"> <svg height="100%" width="100%" viewBox="0 -1 20 10" style="display: block;"> <defs> <linearGradient id="grad"> <stop offset="0" style="stop-color:black" /> <stop offset="1" style="stop-color:magenta" /> </linearGradient> </defs> </svg> </div> """ _scripts = { "render": """ state.initialized = false state.GradientReader = function(colorStops) { const canvas = document.createElement('canvas'); // create canvas element const ctx = canvas.getContext('2d'); // get context const gr = ctx.createLinearGradient(0, 0, 101, 0); // create a gradient canvas.width = 101; // 101 pixels incl. canvas.height = 1; // as the gradient for (const { stop, color } of colorStops) { // add color stops gr.addColorStop(stop, color); } ctx.fillStyle = gr; // set as fill style ctx.fillRect(0, 0, 101, 1); // draw a single line // method to get color of gradient at % position [0, 100] return { getColor: (pst) => { const color_array = ctx.getImageData(pst|0, 0, 1, 1).data return `rgb(${color_array[0]}, ${color_array[1]}, ${color_array[2]})` } }; } state.container = document.getElementById(`arcprog-${data.id}`) const svg = state.container.querySelector("svg") const empty_path = document.createElementNS("http://www.w3.org/2000/svg", "path") empty_path.setAttribute("d", "M1 9 A 8 8 0 1 1 19 9") empty_path.setAttribute("fill", "none") empty_path.setAttribute("stroke-width", "1.5") state.empty_path = empty_path const fill_path = empty_path.cloneNode() state.fill_path = fill_path text = document.createElementNS("http://www.w3.org/2000/svg", "text") text.setAttribute("y","8.9") text.setAttribute("x","10") self.text_style() state.text = text //path used to const external_path = document.createElementNS("http://www.w3.org/2000/svg", "path") external_path.setAttribute("d", "M0.25 9 A 8.75 8.75 0 1 1 19.75 9") state.external_path = external_path svg.appendChild(empty_path) svg.appendChild(fill_path) svg.appendChild(text) self.viewbox() self.transition_duration() self.empty_color() self.fill_color() self.format_options() self.gradient() self.progress() self.annotations() state.initialized = true """, "annotations": """ const path_len = state.empty_path.getTotalLength() const tot_len = state.external_path.getTotalLength() const svg = state.container.querySelector("svg") svg.querySelectorAll(".ArcProgressIndicator_annotation").forEach((node) => node.remove()) const annotations = data.annotations annotations.forEach((annotation) => { const {progress, text, tick_width, text_size} = annotation const annotation_position = state.external_path.getPointAtLength(tot_len * progress/100); const annot_tick = state.empty_path.cloneNode() annot_tick.setAttribute("class", "ArcProgressIndicator_annotation") annot_tick.setAttribute("stroke-dasharray", `${tick_width} ${path_len}`) annot_tick.setAttribute("stroke-dashoffset", `${-(path_len * progress/100 - tick_width/2)}`) annot_tick.setAttribute("stroke", "black") const annot_text = document.createElementNS("http://www.w3.org/2000/svg", "text") annot_text.setAttribute("class", "ArcProgressIndicator_annotation") annot_text.setAttribute("x",annotation_position.x) annot_text.setAttribute("y",annotation_position.y) annot_text.setAttribute("style",`font-size:${text_size};text-anchor:${progress>50 ? "start" : "end"}`) const textNode = document.createTextNode(text) annot_text.appendChild(textNode) svg.appendChild(annot_tick) svg.appendChild(annot_text) }) """, "progress": """ const textNode = document.createTextNode(`${state.formatter.format(data.progress / (state.formatter.resolvedOptions().style=="percent" ? 100 : 1))}`) if(state.text.firstChild) state.text.firstChild.replaceWith(textNode) else text.appendChild(textNode) const path_len = state.empty_path.getTotalLength() state.fill_path.setAttribute("stroke-dasharray", `${path_len * data.progress/100} ${path_len}`) const current_color = data.use_gradient ? state.gr.getColor(data.progress) : data.fill_color if(!state.text_style || !("fill" in state.text_style)) state.text.setAttribute("fill", current_color) """, "transition_duration": """ state.fill_path.setAttribute("style", `transition: stroke-dasharray ${data.transition_duration}s`) """, "format_options": """ state.formatter = new Intl.NumberFormat(data.format_options.locale, data.format_options) if (state.initialized) self.progress() """, "text_style": """ text.setAttribute("style", Object.entries(data.text_style).map(([k, v]) => `${k}:${v}`).join(';')) """, "empty_color": """ state.empty_path.setAttribute("stroke", data.empty_color) """, "fill_color": """ if (data.use_gradient) state.fill_path.setAttribute("stroke", `url(#grad-${data.id}`) else state.fill_path.setAttribute("stroke", data.fill_color) """, "use_gradient": """ self.fill_color() if (state.initialized) self.progress() """, "gradient": """ const gradientNode = state.container.querySelector("linearGradient") gradientNode.querySelectorAll("stop").forEach((stop) => gradientNode.removeChild(stop)) const list_gradient_values = data.gradient list_gradient_values.forEach((elem) => { const stopNode = document.createElementNS("http://www.w3.org/2000/svg", "stop") stopNode.setAttribute("offset", `${elem.stop}`) stopNode.setAttribute("stop-color", `${elem.color}`) gradientNode.appendChild(stopNode) }) state.gr = new state.GradientReader(data.gradient) if (state.initialized) self.progress() """, "viewbox": """ const svg = state.container.querySelector("svg") svg.setAttribute("viewBox", data.viewbox.join(" ")) """ } def __init__(self, **params): if "text_style" in params: default_text_style = dict(self.param.text_style.default) default_text_style.update(params.get("text_style")) params["text_style"] = default_text_style if "format_options" in params: default_format_options = dict(self.param.format_options.default) default_format_options.update(params.get("format_options")) params["format_options"] = default_format_options super().__init__(**params) self._on_use_gradient_change() @pn.depends("use_gradient", watch=True) def _on_use_gradient_change(self): if self.use_gradient: self.param.fill_color.precedence = -1 self.param.gradient.precedence = 1 else: self.param.fill_color.precedence = 1 self.param.gradient.precedence = -1
class NGL(ReactiveHTML): """ The [NGL Viewer](https://github.com/nglviewer/ngl) can be used to show and analyse pdb molecule structures See also panel-chemistry for bokeh implementation: https://github.com/MarcSkovMadsen/panel-chemistry """ object = param.String() extension = param.Selector( default="pdb", objects=EXTENSIONS, ) background_color = param.Color(default="#F7F7F7", doc="Color to use for the background") representation = param.Selector( default="ball+stick", objects=REPRESENTATIONS, doc=""" A display representation. Default is 'ball+stick'. See http://nglviewer.org/ngl/api/manual/coloring.html#representations """, ) color_scheme = param.Selector(default="chainid", objects=COLOR_SCHEMES) custom_color_scheme = param.List( default=[["#258fdb", "*"]], doc=""" A custom color scheme. See http://nglviewer.org/ngl/api/manual/coloring.html#custom-coloring.""", ) effect = param.Selector(default=None, objects=[None, "spin", "rock"], allow_None=True) _template = """ <div id="ngl_stage" style="width:100%; height:100%;"></div> """ _scripts = { "render": """ var stage = new NGL.Stage(ngl_stage) state._stage = stage state._stage.setParameters({ backgroundColor: data.background_color}) stage.handleResize(); self.updateStage() """, "object": """ self.updateStage() """, "color_scheme": """ self.setParameters() """, "custom_color_scheme": """ self.setParameters() """, "background_color": """ state._stage.setParameters({ backgroundColor: data.background_color}) """, "setParameters": """ if (state._stage.compList.length !== 0) { const parameters = self.getParameters(); state._stage.compList[0].reprList[0].setParameters( parameters ); } """, "getParameters": """ if (data.color_scheme==="custom"){ var scheme = NGL.ColormakerRegistry.addSelectionScheme( data.custom_color_scheme, "new scheme") var parameters = {color: scheme} } else { var parameters = {colorScheme: data.color_scheme} } parameters["sele"] = 'protein' return parameters """, "representation": """ const parameters = self.getParameters(); const component = state._stage.compList[0]; component.removeAllRepresentations(); component.addRepresentation(data.representation, parameters); """, "effect": """ if (data.effect==="spin"){ state._stage.setSpin(true); } else if (data.effect==="rock"){ state._stage.setRock(true); } else { state._stage.setSpin(false); state._stage.setRock(false); } """, "updateStage": """ parameters = self.getParameters(); state._stage.removeAllComponents() state._stage.loadFile(new Blob([data.object], {type: 'text/plain'}), { ext: data.extension}).then(function (component) { component.addRepresentation(data.representation, parameters); component.autoView(); }); """, "after_layout": """ state._stage.handleResize(); """, } __javascript__ = [ "https://unpkg.com/[email protected]/dist/ngl.js", ]
class LoadingStyler(param.Parameterized): """A utility that can be used to select and style the loading spinner""" spinner = param.ObjectSelector(default=DEFAULT_URL, objects=config.SPINNERS, doc="The loading spinner to use") spinner_height = param.Integer(50, bounds=(1, 100)) background_rgb = param.Tuple((255, 255, 255)) background_alpha = param.Number(0.5, bounds=(0.0, 1.0), step=0.01, doc="The background alpha") color = param.Color(config.DEFAULT_COLOR) style = param.String("", doc="The CSS Style applied to the loading spinner") settings_panel = param.Parameter( doc="A panel containing the settings of the LoadingStyler") style_panel = param.Parameter( doc="An 'invisible' HTML pane containing the css style") def __init__(self, **params): super().__init__(**params) self.settings_panel = pn.Param( self, parameters=[ "spinner", "spinner_height", "background_alpha", "color", "style", ], widgets={ "style": { "type": pn.widgets.TextAreaInput, "sizing_mode": "stretch_both", "disabled": True, } }, ) self.style_panel = pn.pane.HTML(sizing_mode="fixed", width=0, height=0, margin=0) self._toggle_color() self._update_style() @property def _spinner_url(self): spinner = self.spinner if callable(spinner): return spinner(self.color) # pylint: disable=not-callable return spinner @param.depends("spinner", watch=True) def _toggle_color(self): color_picker: pn.widgets.ColorPicker = [ widget for widget in self.settings_panel if isinstance(widget, pn.widgets.ColorPicker) ][0] color_picker.disabled = not callable(self.spinner) @param.depends("spinner", "spinner_height", "color", "background_rgb", "background_alpha", watch=True) def _update_style(self): self.style = f""" .bk.pn-loading:before {{ background-image: url('{self._spinner_url}'); background-size: auto {self.spinner_height}%; background-color: rgb({self.background_rgb[0]},{self.background_rgb[1]},{self.background_rgb[2]},{self.background_alpha}); }}""" @param.depends("style", watch=True) def _update_loading_spinner_css(self): self.style_panel.object = f"""<style>{self.style}</style>"""
class Q(param.Parameterized): q = param.Color('red', allow_named=False)
class FastStyle(param.Parameterized): """ The FastStyle class provides the different colors and icons used to style the Fast Templates. """ accent_fill_active = param.Color(default="#E45A8C") accent_fill_hover = param.Color(default="#DF3874") accent_fill_rest = param.Color(default="#A01346") accent_foreground_active = param.Color(default="#BA1651") accent_foreground_cut = param.Color(default="#000000") accent_foreground_hover = param.Color(default="#7A0F35") accent_foreground_rest = param.Color(default="#A01346") neutral_outline_active = param.Color(default="#D6D6D6") neutral_outline_hover = param.Color(default="#979797") neutral_outline_rest = param.Color(default="#BEBEBE") accent_base_color = param.Color(default="#A01346") background_color = param.Color(default="#ffffff") collapsed_icon = param.String(default=COLLAPSED_SVG_ICON) expanded_icon = param.String(default=EXPANDED_SVG_ICON) color = param.Color(default="#00aa41") neutral_fill_card_rest = param.Color(default="#F7F7F7") neutral_focus = param.Color(default="#888888") neutral_foreground_rest = param.Color(default="#2B2B2B") header_background = param.Color(default="#00aa41") header_color = param.Color(default="#ffffff") font = param.String(default="Open Sans, sans-serif") font_url = param.String(default=FONT_URL) def create_bokeh_theme(self): """Returns a custom bokeh theme based on the style parameters Returns: Dict: A Bokeh Theme """ return { "attrs": { "Figure": { "background_fill_color": self.background_color, "border_fill_color": self.neutral_fill_card_rest, "border_fill_alpha": 0, "outline_line_color": self.neutral_focus, "outline_line_alpha": 0.5, "outline_line_width": 1, }, "Grid": { "grid_line_color": self.neutral_focus, "grid_line_alpha": 0.25 }, "Axis": { "major_tick_line_alpha": 0, "major_tick_line_color": self.neutral_foreground_rest, "minor_tick_line_alpha": 0, "minor_tick_line_color": self.neutral_foreground_rest, "axis_line_alpha": 0, "axis_line_color": self.neutral_foreground_rest, "major_label_text_color": self.neutral_foreground_rest, "major_label_text_font": self.font, "major_label_text_font_size": "1.025em", "axis_label_standoff": 10, "axis_label_text_color": self.neutral_foreground_rest, "axis_label_text_font": self.font, "axis_label_text_font_size": "1.25em", "axis_label_text_font_style": "normal", }, "Legend": { "spacing": 8, "glyph_width": 15, "label_standoff": 8, "label_text_color": self.neutral_foreground_rest, "label_text_font": self.font, "label_text_font_size": "1.025em", "border_line_alpha": 0.5, "border_line_color": self.neutral_focus, "background_fill_alpha": 0.25, "background_fill_color": self.neutral_fill_card_rest, }, "ColorBar": { "title_text_color": self.neutral_foreground_rest, "title_text_font": self.font, "title_text_font_size": "1.025em", "title_text_font_style": "normal", "major_label_text_color": self.neutral_foreground_rest, "major_label_text_font": self.font, "major_label_text_font_size": "1.025em", # "background_fill_color": FAST_DARK_75, "major_tick_line_alpha": 0, "bar_line_alpha": 0, }, "Title": { "text_color": self.neutral_foreground_rest, "text_font": self.font, "text_font_size": "1.15em", }, } }
class Q(param.Parameterized): q = param.Color()
class ColorPalette(param.Parameterized): # pylint: disable=too-many-instance-attributes """A Material Design Color Palette """ color_50 = param.Color(default="#f3e5f6", precedence=0.0) color_100 = param.Color(default="#e1bee7", precedence=0.1) color_200 = param.Color(default="#ce93d8", precedence=0.2) color_300 = param.Color(default="#ba68c8", precedence=0.3) color_400 = param.Color(default="#ab47bc", precedence=0.4) color_500 = param.Color(default="#9c27b0", precedence=0.5) color_600 = param.Color(default="#9423a9", precedence=0.6) color_700 = param.Color(default="#8a1da0", precedence=0.7) color_800 = param.Color(default="#801797", precedence=0.8) color_900 = param.Color(default="#6e0e87", precedence=0.9) color_a100 = param.Color(default="#efb8ff", precedence=1.1) color_a200 = param.Color(default="#e485ff", precedence=1.2) color_a400 = param.Color(default="#d852ff", precedence=1.4) color_a700 = param.Color(default="#d238ff", precedence=1.7) contrast_50 = param.ObjectSelector(default=color.DARK_PRIMARY_TEXT, objects=color.PRIMARY_TEXTS, precedence=0.0) contrast_100 = param.ObjectSelector(default=color.DARK_PRIMARY_TEXT, objects=color.PRIMARY_TEXTS, precedence=0.1) contrast_200 = param.ObjectSelector(default=color.DARK_PRIMARY_TEXT, objects=color.PRIMARY_TEXTS, precedence=0.2) contrast_300 = param.ObjectSelector(default=color.DARK_PRIMARY_TEXT, objects=color.PRIMARY_TEXTS, precedence=0.3) contrast_400 = param.ObjectSelector(default=color.LIGHT_PRIMARY_TEXT, objects=color.PRIMARY_TEXTS, precedence=0.4) contrast_500 = param.ObjectSelector(default=color.LIGHT_PRIMARY_TEXT, objects=color.PRIMARY_TEXTS, precedence=0.5) contrast_600 = param.ObjectSelector(default=color.LIGHT_PRIMARY_TEXT, objects=color.PRIMARY_TEXTS, precedence=0.6) contrast_700 = param.ObjectSelector(default=color.LIGHT_PRIMARY_TEXT, objects=color.PRIMARY_TEXTS, precedence=0.7) contrast_800 = param.ObjectSelector(default=color.LIGHT_PRIMARY_TEXT, objects=color.PRIMARY_TEXTS, precedence=0.8) contrast_900 = param.ObjectSelector(default=color.LIGHT_PRIMARY_TEXT, objects=color.PRIMARY_TEXTS, precedence=0.9) contrast_a100 = param.ObjectSelector(default=color.DARK_PRIMARY_TEXT, objects=color.PRIMARY_TEXTS, precedence=1.1) contrast_a200 = param.ObjectSelector(default=color.DARK_PRIMARY_TEXT, objects=color.PRIMARY_TEXTS, precedence=1.2) contrast_a400 = param.ObjectSelector(default=color.DARK_PRIMARY_TEXT, objects=color.PRIMARY_TEXTS, precedence=1.4) contrast_a700 = param.ObjectSelector(default=color.LIGHT_PRIMARY_TEXT, objects=color.PRIMARY_TEXTS, precedence=1.7) @param.depends("color_500", watch=True) def _update_colors_from_color_500(self): colors = compute_colors(self.color_500) self.color_50 = colors["50"] self.color_100 = colors["100"] self.color_200 = colors["200"] self.color_300 = colors["300"] self.color_400 = colors["400"] # self.color_500 = colors["500"] self.color_600 = colors["600"] self.color_700 = colors["700"] self.color_800 = colors["800"] self.color_900 = colors["900"] self.color_a100 = colors["A100"] self.color_a200 = colors["A200"] self.color_a400 = colors["A400"] self.color_a700 = colors["A700"] self.contrast_50 = (color.LIGHT_PRIMARY_TEXT if is_dark(self.color_50) else color.DARK_PRIMARY_TEXT) self.contrast_100 = (color.LIGHT_PRIMARY_TEXT if is_dark( self.color_100) else color.DARK_PRIMARY_TEXT) self.contrast_200 = (color.LIGHT_PRIMARY_TEXT if is_dark( self.color_200) else color.DARK_PRIMARY_TEXT) self.contrast_300 = (color.LIGHT_PRIMARY_TEXT if is_dark( self.color_300) else color.DARK_PRIMARY_TEXT) self.contrast_400 = (color.LIGHT_PRIMARY_TEXT if is_dark( self.color_400) else color.DARK_PRIMARY_TEXT) self.contrast_500 = (color.LIGHT_PRIMARY_TEXT if is_dark( self.color_500) else color.DARK_PRIMARY_TEXT) self.contrast_600 = (color.LIGHT_PRIMARY_TEXT if is_dark( self.color_600) else color.DARK_PRIMARY_TEXT) self.contrast_700 = (color.LIGHT_PRIMARY_TEXT if is_dark( self.color_700) else color.DARK_PRIMARY_TEXT) self.contrast_800 = (color.LIGHT_PRIMARY_TEXT if is_dark( self.color_800) else color.DARK_PRIMARY_TEXT) self.contrast_900 = (color.LIGHT_PRIMARY_TEXT if is_dark( self.color_900) else color.DARK_PRIMARY_TEXT) self.contrast_a100 = (color.LIGHT_PRIMARY_TEXT if is_dark( self.color_a100) else color.DARK_PRIMARY_TEXT) self.contrast_a200 = (color.LIGHT_PRIMARY_TEXT if is_dark( self.color_a200) else color.DARK_PRIMARY_TEXT) self.contrast_a400 = (color.LIGHT_PRIMARY_TEXT if is_dark( self.color_a400) else color.DARK_PRIMARY_TEXT) self.contrast_a700 = (color.LIGHT_PRIMARY_TEXT if is_dark( self.color_a700) else color.DARK_PRIMARY_TEXT) def editor(self) -> pn.Column: """Returns an editor from that enables the user to edit the Color Palette. Returns: [pn.Column]: An Color Palette Editor """ return pn.Column( "## Color Palette Editor", pn.Param( self, show_name=False, parameters=COLOR_PARAMETERS, ), ) def color_500_editor(self) -> pn.Column: """Returns an editor that enables the user to edit the Color 500. Returns: pn.Column: [description] """ return pn.Column( "## Color Palette Editor", self.param.color_500, self.readonly_view(), ) def to_html_table(self) -> str: """Returns a HTML string that shows the color palette""" return f"""\ <table style="width:100%;text-align:center"><tbody> <tr style="background-color:{self.color_50};color:{self.contrast_50}"><td>50: </td><td>{self.color_50}</td></tr> <tr style="background-color:{self.color_100};color:{self.contrast_100}"><td>100: </td><td>{self.color_100}</td></tr> <tr style="background-color:{self.color_200};color:{self.contrast_200}"><td>200: </td><td>{self.color_200}</td></tr> <tr style="background-color:{self.color_300};color:{self.contrast_300}"><td>300: </td><td>{self.color_300}</td></tr> <tr style="background-color:{self.color_400};color:{self.contrast_400}"><td>400: </td><td>{self.color_400}</td></tr> <tr style="background-color:{self.color_500};color:{self.contrast_500}"><td>500: </td><td>{self.color_500}</td></tr> <tr style="background-color:{self.color_600};color:{self.contrast_600}"><td>600: </td><td>{self.color_600}</td></tr> <tr style="background-color:{self.color_700};color:{self.contrast_700}"><td>700: </td><td>{self.color_700}</td></tr> <tr style="background-color:{self.color_800};color:{self.contrast_800}"><td>800: </td><td>{self.color_800}</td></tr> <tr style="background-color:{self.color_900};color:{self.contrast_900}"><td>900: </td><td>{self.color_900}</td></tr> <tr style="background-color:{self.color_a100};color:{self.contrast_a100}"><td>A100: </td><td>{self.color_a100}</td></tr> <tr style="background-color:{self.color_a200};color:{self.contrast_a200}"><td>A200: </td><td>{self.color_a200}</td></tr> <tr style="background-color:{self.color_a400};color:{self.contrast_a400}"><td>A400: </td><td>{self.color_a400}</td></tr> <tr style="background-color:{self.color_a700};color:{self.contrast_a700}"><td>A700: </td><td>{self.color_a700}</td></tr> </tbody></table>""" def readonly_view(self) -> pn.Column: """Returns a read only view of the Color Palette Returns: pn.Column: A read only view """ return pn.Column("## Color Palette", pn.pane.HTML(self.to_html_table())) def __eq__(self, other): return self.name == other.name
class VTKVolume(PaneBase): max_data_size = param.Number(default=(256**3) * 2 / 1e6, doc=""" Maximum data size transfert allowed without subsampling""") origin = param.Tuple(default=None, length=3, allow_None=True) spacing = param.Tuple(default=(1, 1, 1), length=3, doc=""" Distance between voxel in each direction""") render_background = param.Color(default='#52576e', doc=""" Allows to specify the background color of the 3D rendering. The value must be specified as an hexadecimal color string """) colormap = param.Selector(default='erdc_rainbow_bright', objects=PRESET_CMAPS, doc=""" Name of the colormap used to transform pixel value in color """) rescale = param.Boolean(default=False, doc=""" If set to True the colormap is rescale beween min and max value of the non transparent pixels Else the full range of the pixel values are used """) shadow = param.Boolean(default=True, doc=""" If set to False, then the mapper for the volume will not perform shading computations, it is the same as setting ambient=1, diffuse=0, specular=0 """) sampling = param.Number(default=0.4, bounds=(0, 1), step=1e-2, doc=""" Parameter to adjust the distance between samples used for rendering. The lower the value is the more precise is the representation but it is more computationnaly intensive """) edge_gradient = param.Number(default=0.4, bounds=(0, 1), step=1e-2, doc=""" Parameter to adjust the opacity of the volume based on the gradient between voxels """) interpolation = param.Selector( default='fast_linear', objects=['fast_linear', 'linear', 'nearest'], doc=""" interpolation type for sampling a volume. `nearest` interpolation will snap to the closest voxel, `linear` will perform trilinear interpolation to compute a scalar value from surrounding voxels. `fast_linear` under WebGL 1 will perform bilinear interpolation on X and Y but use nearest for Z. This is slightly faster than full linear at the cost of no Z axis linear interpolation. """) ambient = param.Number(default=0.2, step=1e-2, doc=""" Value to control the ambient lighting. It is the light an object gives even in the absence of strong light. It is constant in all directions. """) diffuse = param.Number(default=0.7, step=1e-2, doc=""" Value to control the diffuse Lighting. It relies on both the light direction and the object surface normal. """) specular = param.Number(default=0.3, step=1e-2, doc=""" Value to control specular lighting. It is the light reflects back toward the camera when hitting the object """) specular_power = param.Number(default=8., doc=""" Specular power refers to how much light is reflected in a mirror like fashion, rather than scattered randomly in a diffuse manner """) slice_i = param.Integer(per_instance=True, doc=""" Integer parameter to control the position of the slice normal to the X direction """) slice_j = param.Integer(per_instance=True, doc=""" Integer parameter to control the position of the slice normal to the Y direction """) slice_k = param.Integer(per_instance=True, doc=""" Integer parameter to control the position of the slice normal to the Z direction """) display_volume = param.Boolean(default=True, doc=""" If set to True, the 3D respresentation of the volume is displayed using ray casting """) display_slices = param.Boolean(default=False, doc=""" If set to true, the orthgonal slices in the three (X, Y, Z) directions are displayed. Postition of each slice can be controlled using slice_(i,j,k) parameters """) _serializers = {} _rename = {'max_data_size': None, 'spacing': None, 'origin': None} _updates = True def __init__(self, object=None, **params): super(VTKVolume, self).__init__(object, **params) self._sub_spacing = self.spacing self._volume_data = self._get_volume_data() if self._volume_data: self.param.slice_i.bounds = (0, self._volume_data['dims'][0] - 1) self.slice_i = (self._volume_data['dims'][0] - 1) // 2 self.param.slice_j.bounds = (0, self._volume_data['dims'][1] - 1) self.slice_j = (self._volume_data['dims'][1] - 1) // 2 self.param.slice_k.bounds = (0, self._volume_data['dims'][2] - 1) self.slice_k = (self._volume_data['dims'][2] - 1) // 2 @classmethod def applies(cls, obj): if ((isinstance(obj, np.ndarray) and obj.ndim == 3) or any([isinstance(obj, k) for k in cls._serializers.keys()])): return True elif 'vtk' not in sys.modules: return False else: import vtk return isinstance(obj, vtk.vtkImageData) def _get_model(self, doc, root=None, parent=None, comm=None): """ Should return the bokeh model to be rendered. """ if 'panel.models.vtk' not in sys.modules: if isinstance(comm, JupyterComm): self.param.warning( 'VTKVolumePlot was not imported on instantiation ' 'and may not render in a notebook. Restart ' 'the notebook kernel and ensure you load ' 'it as part of the extension using:' '\n\npn.extension(\'vtk\')\n') from ...models.vtk import VTKVolumePlot else: VTKVolumePlot = getattr(sys.modules['panel.models.vtk'], 'VTKVolumePlot') props = self._process_param_change(self._init_properties()) volume_data = self._volume_data model = VTKVolumePlot(data=volume_data, **props) if root is None: root = model self._link_props(model, ['colormap'], doc, root, comm) self._models[root.ref['id']] = (model, parent) return model def _update_object(self, ref, doc, root, parent, comm): self._legend = None super(VTKVolume, self)._update_object(ref, doc, root, parent, comm) def _init_properties(self): return { k: v for k, v in self.param.get_param_values() if v is not None and k not in ['default_layout', 'object', 'max_data_size', 'spacing', 'origin'] } def _update(self, model): self._volume_data = self._get_volume_data() if self._volume_data: self.param.slice_i.bounds = (0, self._volume_data['dims'][0] - 1) self.slice_i = (self._volume_data['dims'][0] - 1) // 2 self.param.slice_j.bounds = (0, self._volume_data['dims'][1] - 1) self.slice_j = (self._volume_data['dims'][1] - 1) // 2 self.param.slice_k.bounds = (0, self._volume_data['dims'][2] - 1) self.slice_k = (self._volume_data['dims'][2] - 1) // 2 model.data = self._volume_data @classmethod def register_serializer(cls, class_type, serializer): """ Register a seriliazer for a given type of class. A serializer is a function which take an instance of `class_type` (like a vtk.vtkImageData) as input and return a numpy array of the data """ cls._serializers.update({class_type: serializer}) def _volume_from_array(self, sub_array): return dict( buffer=base64encode( sub_array.ravel( order='F' if sub_array.flags['F_CONTIGUOUS'] else 'C')), dims=sub_array.shape if sub_array.flags['F_CONTIGUOUS'] else sub_array.shape[::-1], spacing=self._sub_spacing if sub_array.flags['F_CONTIGUOUS'] else self._sub_spacing[::-1], origin=self.origin, data_range=(sub_array.min(), sub_array.max()), dtype=sub_array.dtype.name) def _get_volume_data(self): if self.object is None: return None elif isinstance(self.object, np.ndarray): return self._volume_from_array(self._subsample_array(self.object)) else: available_serializer = [ v for k, v in self._serializers.items() if isinstance(self.object, k) ] if not available_serializer: import vtk from vtk.util import numpy_support def volume_serializer(imageData): array = numpy_support.vtk_to_numpy( imageData.GetPointData().GetScalars()) dims = imageData.GetDimensions()[::-1] self.spacing = imageData.GetSpacing()[::-1] self.origin = imageData.GetOrigin() return self._volume_from_array( self._subsample_array(array.reshape(dims, order='C'))) self.register_serializer(vtk.vtkImageData, volume_serializer) serializer = volume_serializer else: serializer = available_serializer[0] return serializer(self.object) def _subsample_array(self, array): original_shape = array.shape spacing = self.spacing extent = tuple( (o_s - 1) * s for o_s, s in zip(original_shape, spacing)) dim_ratio = np.cbrt( (np.prod(original_shape) / 1e6) / self.max_data_size) max_shape = tuple(int(o_s / dim_ratio) for o_s in original_shape) dowsnscale_factor = [ max(o_s, m_s) / m_s for m_s, o_s in zip(max_shape, original_shape) ] if any([d_f > 1 for d_f in dowsnscale_factor]): try: import scipy.ndimage as nd sub_array = nd.interpolation.zoom( array, zoom=[1 / d_f for d_f in dowsnscale_factor], order=0) except ImportError: sub_array = array[::int(np.ceil(dowsnscale_factor[0])), ::int( np.ceil(dowsnscale_factor[1]) ), ::int(np.ceil(dowsnscale_factor[2]))] self._sub_spacing = tuple(e / (s - 1) for e, s in zip(extent, sub_array.shape)) else: sub_array = array self._sub_spacing = self.spacing return sub_array
class Q(param.Parameterized): q = param.Color(allow_named=True)