def _get_model(self, doc, root=None, parent=None, comm=None): if root is None: return self._get_root(doc, comm) if self.object is None: model = BkSpacer() else: model = self.object properties = {} for p, value in self.param.values().items(): if (p not in Layoutable.param or p == 'name' or value is self.param[p].default): continue properties[p] = value model.update(**properties) if comm: self._wrap_bokeh_callbacks(root, model, doc, comm) ref = root.ref['id'] for js in model.select({'type': CustomJS}): js.code = js.code.replace(model.ref['id'], ref) if model._document and doc is not model._document: remove_root(model, doc) self._models[ref] = (model, parent) if self.theme: doc.theme = self.theme return model
def _get_objects(self, model, old_objects, doc, root, comm=None): """ Returns new child models for the layout while reusing unchanged models and cleaning up any dropped objects. """ from .pane.base import RerenderError, panel new_models = [] if len(self._names) != len(self): raise ValueError('Tab names do not match objects, ensure ' 'that the Tabs.objects are not modified ' 'directly. Found %d names, expected %d.' % (len(self._names), len(self))) for i, (name, pane) in enumerate(zip(self._names, self)): pane = panel(pane, name=name) self.objects[i] = pane for obj in old_objects: if obj not in self.objects: obj._cleanup(root) current_objects = list(self) panels = self._panels[root.ref['id']] for i, (name, pane) in enumerate(zip(self._names, self)): hidden = self.dynamic and i != self.active if (pane in old_objects and id(pane) in panels and ((hidden and isinstance(panels[id(pane)].child, BkSpacer)) or (not hidden and not isinstance(panels[id(pane)].child, BkSpacer)))): panel = panels[id(pane)] new_models.append(panel) continue elif self.dynamic and i != self.active: child = BkSpacer( **{ k: v for k, v in pane.param.get_param_values() if k in Layoutable.param }) else: try: child = pane._get_model(doc, root, model, comm) except RerenderError: return self._get_objects(model, current_objects[:i], doc, root, comm) panel = panels[id(pane)] = BkPanel(title=name, name=pane.name, child=child, closable=self.closable) new_models.append(panel) return new_models
def _get_model(self, doc, root=None, parent=None, comm=None): model = self._bokeh_model() root = model if root is None else root objects = self._get_objects(model, [], doc, root, comm) # HACK ALERT: Insert Spacer if last item in Column has no height if (isinstance(self, Column) and objects and not has_height(objects[-1])): objects.append(BkSpacer(height=50)) props = dict(self._init_properties(), objects=objects) model.update(**self._process_param_change(props)) params = [p for p in self.params() if p != 'name'] self._models[root.ref['id']] = model self._link_params(model, params, doc, root, comm) self._link_props(model, self._linked_props, doc, root, comm) return model
def _get_objects(self, model, old_objects, doc, root, comm=None): """ Returns new child models for the layout while reusing unchanged models and cleaning up any dropped objects. """ from ..pane.base import RerenderError, panel new_models = [] if len(self._names) != len(self): raise ValueError('Tab names do not match objects, ensure ' 'that the Tabs.objects are not modified ' 'directly. Found %d names, expected %d.' % (len(self._names), len(self))) for i, (name, pane) in enumerate(zip(self._names, self)): pane = panel(pane, name=name) self.objects[i] = pane ref = root.ref['id'] panels = self._panels[ref] rendered = self._rendered[ref] for obj in old_objects: if obj in self.objects: continue obj._cleanup(root) panels.pop(id(obj), None) rendered.pop(id(obj), None) current_objects = list(self) for i, (name, pane) in enumerate(zip(self._names, self)): pref = id(pane) hidden = self.dynamic and i != self.active panel = panels.get(pref) prev_hidden = (hasattr(panel, 'child') and isinstance(panel.child, BkSpacer) and panel.child.tags == ['hidden']) # If object has not changed, we have not toggled between # hidden and unhidden state or the tabs are not # dynamic then reuse the panel if (pane in old_objects and pref in panels and (not (hidden ^ prev_hidden) or not (self.dynamic or prev_hidden))): new_models.append(panel) continue if prev_hidden and not hidden and pref in rendered: child = rendered[pref] elif hidden: child = BkSpacer( **{ k: v for k, v in pane.param.values().items() if k in Layoutable.param and v is not None }) child.tags = ['hidden'] else: try: rendered[pref] = child = pane._get_model( doc, root, model, comm) except RerenderError: return self._get_objects(model, current_objects[:i], doc, root, comm) panel = panels[pref] = BkPanel(title=name, name=pane.name, child=child, closable=self.closable) new_models.append(panel) return new_models
def Div(**kwargs): # Hack to work around issues with Div height in notebooks div = BkDiv(**kwargs) if 'height' in kwargs: return BkRow(div, BkSpacer(height=kwargs['height'])) return div