Cloning tabs gives RuntimeError: Models must be owned by only a single document

Hello,

In my application I have tabs which are dynamically populated. The tabs must be dynamic, because of performance issues. I also need a way to save tabs with all content. To achieve this I need to clone them, as philippjfr suggested in another topic (thanks!).

This cloning however leads to another problem, which can be illustrated with the following example:

import panel as pn
import holoviews as hv
import numpy as np
from bokeh.models import NumeralTickFormatter
hv.extension("bokeh")

def make_img(**opts):
    ls = np.linspace(0, 10, 200)
    xx, yy = np.meshgrid(ls, ls)
    bounds=(-1,-1,1,1)   # Coordinate system: (left, bottom, right, top)
    return hv.Image(np.sin(xx)*np.cos(yy), bounds=bounds).opts(**opts)

img1 = make_img(xformatter=NumeralTickFormatter())
img2 = make_img(cmap="jet")
tabs = pn.Tabs(img1, img2, dynamic=True)

def save_tabs(event):
    tabs.clone(dynamic=False).save("tmp.html", embed=True, resources="INLINE")

save_button = pn.widgets.Button(name="Save tabs")
save_button.on_click(save_tabs)

pn.Row(tabs, save_button)

On the first plot I need a custom tick formatter. When I switch to the second tab, and then click save button, the file gets saved correctly. However, when I try to come back to the first tab, I get the following error:

Traceback (most recent call last):
  File "/opt/conda/lib/python3.7/site-packages/pyviz_comms/__init__.py", line 325, in _handle_msg
    self._on_msg(msg)
  File "/opt/conda/lib/python3.7/site-packages/panel/viewable.py", line 259, in _on_msg
    doc.unhold()
  File "/opt/conda/lib/python3.7/site-packages/bokeh/document/document.py", line 668, in unhold
    self._trigger_on_change(event)
  File "/opt/conda/lib/python3.7/site-packages/bokeh/document/document.py", line 1151, in _trigger_on_change
    self._with_self_as_curdoc(event.callback_invoker)
  File "/opt/conda/lib/python3.7/site-packages/bokeh/document/document.py", line 1169, in _with_self_as_curdoc
    return f()
  File "/opt/conda/lib/python3.7/site-packages/bokeh/util/callback_manager.py", line 155, in invoke
    callback(attr, old, new)
  File "/opt/conda/lib/python3.7/site-packages/panel/layout/tabs.py", line 92, in _comm_change
    super(Tabs, self)._comm_change(doc, ref, comm, attr, old, new)
  File "/opt/conda/lib/python3.7/site-packages/panel/reactive.py", line 216, in _comm_change
    self._process_events({attr: new})
  File "/opt/conda/lib/python3.7/site-packages/panel/reactive.py", line 187, in _process_events
    self.param.set_param(**self._process_property_change(events))
  File "/opt/conda/lib/python3.7/site-packages/param/parameterized.py", line 1472, in set_param
    self_._batch_call_watchers()
  File "/opt/conda/lib/python3.7/site-packages/param/parameterized.py", line 1611, in _batch_call_watchers
    self_._execute_watcher(watcher, events)
  File "/opt/conda/lib/python3.7/site-packages/param/parameterized.py", line 1573, in _execute_watcher
    watcher.fn(*args, **kwargs)
  File "/opt/conda/lib/python3.7/site-packages/panel/layout/tabs.py", line 107, in _update_active
    self.param.trigger('objects')
  File "/opt/conda/lib/python3.7/site-packages/param/parameterized.py", line 1541, in trigger
    self_.set_param(**dict(params, **triggers))
  File "/opt/conda/lib/python3.7/site-packages/param/parameterized.py", line 1472, in set_param
    self_._batch_call_watchers()
  File "/opt/conda/lib/python3.7/site-packages/param/parameterized.py", line 1611, in _batch_call_watchers
    self_._execute_watcher(watcher, events)
  File "/opt/conda/lib/python3.7/site-packages/param/parameterized.py", line 1573, in _execute_watcher
    watcher.fn(*args, **kwargs)
  File "/opt/conda/lib/python3.7/site-packages/panel/reactive.py", line 175, in _param_change
    self._update_model(events, msg, root, model, doc, comm)
  File "/opt/conda/lib/python3.7/site-packages/panel/layout/tabs.py", line 120, in _update_model
    super(Tabs, self)._update_model(events, msg, root, model, doc, comm)
  File "/opt/conda/lib/python3.7/site-packages/panel/layout/base.py", line 65, in _update_model
    super(Panel, self)._update_model(events, msg, root, model, doc, comm)
  File "/opt/conda/lib/python3.7/site-packages/panel/reactive.py", line 137, in _update_model
    model.update(**msg)
  File "/opt/conda/lib/python3.7/site-packages/bokeh/core/has_props.py", line 374, in update
    setattr(self, k, v)
  File "/opt/conda/lib/python3.7/site-packages/bokeh/core/has_props.py", line 278, in __setattr__
    super().__setattr__(name, value)
  File "/opt/conda/lib/python3.7/site-packages/bokeh/core/property/descriptors.py", line 539, in __set__
    self._internal_set(obj, value, setter=setter)
  File "/opt/conda/lib/python3.7/site-packages/bokeh/core/property/descriptors.py", line 763, in _internal_set
    self._real_set(obj, old, value, hint=hint, setter=setter)
  File "/opt/conda/lib/python3.7/site-packages/bokeh/core/property/descriptors.py", line 832, in _real_set
    self._trigger(obj, old, value, hint=hint, setter=setter)
  File "/opt/conda/lib/python3.7/site-packages/bokeh/core/property/descriptors.py", line 909, in _trigger
    obj.trigger(self.name, old, value, hint, setter)
  File "/opt/conda/lib/python3.7/site-packages/bokeh/model.py", line 662, in trigger
    self._document._invalidate_all_models()
  File "/opt/conda/lib/python3.7/site-packages/bokeh/document/document.py", line 1031, in _invalidate_all_models
    self._recompute_all_models()
  File "/opt/conda/lib/python3.7/site-packages/bokeh/document/document.py", line 1098, in _recompute_all_models
    a._attach_document(self)
  File "/opt/conda/lib/python3.7/site-packages/bokeh/model.py", line 674, in _attach_document
    raise RuntimeError("Models must be owned by only a single document, %r is already in a doc" % (self))
RuntimeError: Models must be owned by only a single document, NumeralTickFormatter(id='3112', ...) is already in a doc

Could you help me with solving this?

My env: Python 3.7.6, panel==0.10.3, holoviews==1.14.0, bokeh==2.2.3

Thanks in advance,
Rafał

For future reference: I reported this as a bug Tabs cloning breaks app when containing plots with custom ticks · Issue #2220 · holoviz/panel · GitHub