# Odd behavior when combining pn.param.ParamMethod and pn.Tabs(dynamic=True)

**URL:** <https://discourse.holoviz.org/t/odd-behavior-when-combining-pn-param-parammethod-and-pn-tabs-dynamic-true/6581>\
**Category:** Panel\
**Tags:** param\
**Created:** [December 13, 2023, 5:30pm UTC](https://discourse.holoviz.org/t/odd-behavior-when-combining-pn-param-parammethod-and-pn-tabs-dynamic-true/6581 "2023-12-13T17:30:01Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![LinuxIsCool](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/linuxiscool/32/276_2.png) [@LinuxIsCool](https://discourse.holoviz.org/u/LinuxIsCool)\
**Post date:** [December 13, 2023, 5:30pm UTC](https://discourse.holoviz.org/t/odd-behavior-when-combining-pn-param-parammethod-and-pn-tabs-dynamic-true/6581/1 "2023-12-13T17:30:01Z")

</div>

Consider the following:

```python
import time

import hvplot.pandas
import numpy as np
import pandas as pd
import panel as pn
import param as pm

pn.extension()
pn.config.throttled = True

class A(pm.Parameterized):
    data = pm.DataFrame()
    x = pm.Integer(10, bounds=(1, 100))

    @pm.depends('x', watch=True, on_init=True)
    def update_data(self):
        self.data = pd.DataFrame({'x': list(range(self.x)), 'y': np.ones(self.x)})

    def view_data(self):
        time.sleep(3)
        return self.data.hvplot.line(x='x', y='y')

    def view(self):
        return pn.Tabs(
            ('Object', self),
            ('Data', pn.param.ParamMethod(self.view_data)),
            dynamic=True,
        )

a = pn.panel(A().view())

a.servable()

```

The program works fine if I remove either `pn.param.ParamMethod` or `dynamic=True` but when I have both then the program does not work as expected, as in, after switching between tabs, nothing is displayed. I did get an error as well which said something about circular dependency, but I’m currently unable to reproduce that error.

How can I get the benefits of dynamic tabs and also ParamMethod?  
The reason for using ParamMethod is to get the loading\_indicator functionality.

Thanks!

---

<div class="post-metadata">

**Author:** ![contango](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/contango/32/6401_2.png) [@contango](https://discourse.holoviz.org/u/contango)\
**Post date:** [March 15, 2024, 3:08pm UTC](https://discourse.holoviz.org/t/odd-behavior-when-combining-pn-param-parammethod-and-pn-tabs-dynamic-true/6581/2 "2024-03-15T15:08:42Z")

</div>

I have the same issue when using pn.Param to feed in some inputs together with pn.Tabs and dynamic=True. I cannot post the code right now, but I get the following error when I switch from tab 0 (the active one on startup) to tab 1 and back to tab 0. Tab 0 then becomes blank.

```auto
(03/15/2024 04:10:20 PM) - tornado.application - ERROR - ioloop:758 - Exception in callback functools.partial(<bound method IOLoop._discard_future_result of <tornado.platform.asyncio.AsyncIOMainLoop object at 0x000001B760D9F690>>, <Task finished name='Task-113' coro=<ServerSession.with_document_locked() done, defined at C:\Mambaforge\envs\env\Lib\site-packages\bokeh\server\session.py:77> exception=SerializationError('circular reference')>)
Traceback (most recent call last):
  File "C:\Mambaforge\envs\env\Lib\site-packages\tornado\ioloop.py", line 738, in _run_callback
    ret = callback()
          ^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\tornado\ioloop.py", line 762, in _discard_future_result
    future.result()
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\server\session.py", line 94, in _needs_document_lock_wrapper
    result = func(self, *args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\server\session.py", line 226, in with_document_locked
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\document\callbacks.py", line 485, in wrapper
    return invoke_with_curdoc(doc, invoke)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\document\callbacks.py", line 443, in invoke_with_curdoc
    return f()
           ^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\document\callbacks.py", line 484, in invoke
    return f(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\document\callbacks.py", line 182, in remove_then_invoke
    return callback()
           ^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\panel\layout\base.py", line 114, in _update_model
    with hold(doc):
  File "C:\Mambaforge\envs\env\Lib\contextlib.py", line 144, in __exit__
    next(self.gen)
  File "C:\Mambaforge\envs\env\Lib\site-packages\panel\io\model.py", line 207, in hold
    doc.unhold()
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\document\document.py", line 776, in unhold
    self.callbacks.unhold()
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\document\callbacks.py", line 431, in unhold
    self.trigger_on_change(event)
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\document\callbacks.py", line 413, in trigger_on_change
    invoke_with_curdoc(doc, invoke_callbacks)
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\document\callbacks.py", line 443, in invoke_with_curdoc
    return f()
           ^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\document\callbacks.py", line 412, in invoke_callbacks
    cb(event)
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\document\callbacks.py", line 276, in <lambda>
    self._change_callbacks[receiver] = lambda event: event.dispatch(receiver)
                                                     ^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\document\events.py", line 353, in dispatch
    super().dispatch(receiver)
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\document\events.py", line 219, in dispatch
    cast(DocumentPatchedMixin, receiver)._document_patched(self)
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\server\session.py", line 252, in _document_patched
    self._pending_writes.append(connection.send_patch_document(event))
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\server\connection.py", line 86, in send_patch_document
    msg = self.protocol.create('PATCH-DOC', [event])
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\protocol\ __init__.py", line 131, in create
    return self._messages[msgtype].create(*args, **kwargs) # type: ignore [attr-defined]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\protocol\messages\patch_doc.py", line 90, in create
    patch_json = PatchJson(events=serializer.encode(events))
                                  ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 251, in encode
    return self._encode(obj)
           ^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 276, in _encode
    return self._encode_list(obj)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 322, in _encode_list
    return [self.encode(item) for item in obj]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 322, in <listcomp>
    return [self.encode(item) for item in obj]
            ^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 251, in encode
    return self._encode(obj)
           ^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 260, in _encode
    return obj.to_serializable(self)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\document\events.py", line 369, in to_serializable
    new = serializer.encode(self.new),
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 251, in encode
    return self._encode(obj)
           ^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 280, in _encode
    return self._encode_dict(obj)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 339, in _encode_dict
    entries=[(self.encode(key), self.encode(val)) for key, val in obj.items()],
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 339, in <listcomp>
    entries=[(self.encode(key), self.encode(val)) for key, val in obj.items()],
                                ^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 251, in encode
    return self._encode(obj)
           ^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 276, in _encode
    return self._encode_list(obj)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 322, in _encode_list
    return [self.encode(item) for item in obj]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 322, in <listcomp>
    return [self.encode(item) for item in obj]
            ^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 251, in encode
    return self._encode(obj)
           ^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 260, in _encode
    return obj.to_serializable(self)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\model\model.py", line 525, in to_serializable
    super_rep = super().to_serializable(serializer)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\has_props.py", line 406, in to_serializable
    attributes = {key: serializer.encode(val) for key, val in properties.items()}
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\has_props.py", line 406, in <dictcomp>
    attributes = {key: serializer.encode(val) for key, val in properties.items()}
                       ^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 251, in encode
    return self._encode(obj)
           ^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 280, in _encode
    return self._encode_dict(obj)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 339, in _encode_dict
    entries=[(self.encode(key), self.encode(val)) for key, val in obj.items()],
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 339, in <listcomp>
    entries=[(self.encode(key), self.encode(val)) for key, val in obj.items()],
                                ^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 251, in encode
    return self._encode(obj)
           ^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 260, in _encode
    return obj.to_serializable(self)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\model\model.py", line 525, in to_serializable
    super_rep = super().to_serializable(serializer)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\has_props.py", line 406, in to_serializable
    attributes = {key: serializer.encode(val) for key, val in properties.items()}
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\has_props.py", line 406, in <dictcomp>
    attributes = {key: serializer.encode(val) for key, val in properties.items()}
                       ^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 247, in encode
    self.error("circular reference")
  File "C:\Mambaforge\envs\env\Lib\site-packages\bokeh\core\serialization.py", line 468, in error
    raise SerializationError(message)
bokeh.core.serialization.SerializationError: circular reference

```

---

<div class="post-metadata">

**Author:** ![ahuang11](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/ahuang11/32/4947_2.png) [@ahuang11](https://discourse.holoviz.org/u/ahuang11)\
**Post date:** [March 15, 2024, 9:31pm UTC](https://discourse.holoviz.org/t/odd-behavior-when-combining-pn-param-parammethod-and-pn-tabs-dynamic-true/6581/3 "2024-03-15T21:31:08Z")

</div>

I think this might have been fixed in Panel main; `pip install panel==1.4.0rc2`

Also, if you want, you can make it async so you can use yield to first show loading, then the desired output.

```python
import asyncio
import time

import hvplot.pandas
import numpy as np
import pandas as pd
import panel as pn
import param as pm

pn.extension()
pn.config.throttled = True

class A(pm.Parameterized):
    data = pm.DataFrame()
    x = pm.Integer(10, bounds=(1, 100))

    @pm.depends('x', watch=True, on_init=True)
    def update_data(self):
        self.data = pd.DataFrame({'x': list(range(self.x)), 'y': np.ones(self.x)})

    async def view_data(self):
        yield "Loading..."
        await asyncio.sleep(2)
        yield self.data.hvplot.line(x='x', y='y')

    def view(self):
        return pn.Tabs(
            ('Object', self),
            ('Data', pn.param.ParamMethod(self.view_data)),
            dynamic=True,
        )

a = pn.panel(A().view())

a.servable()

```

---

<div class="post-metadata">

**Author:** ![contango](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/contango/32/6401_2.png) [@contango](https://discourse.holoviz.org/u/contango)\
**Post date:** [March 18, 2024, 8:46am UTC](https://discourse.holoviz.org/t/odd-behavior-when-combining-pn-param-parammethod-and-pn-tabs-dynamic-true/6581/5 "2024-03-18T08:46:47Z")

</div>

Unfortunately the bug seems to persist, I still get the circular reference error. Please find the below code to reproduce the issue.

```auto
import logging

import panel as pn
import param

class Test(param.Parameterized):
    load_button = param.Action(label="Load..")
    extract_button = param.Action(label="Extract..")    

    def __init__ (self, **params):
        super(Test, self). __init__ (**params)

    def init_panel(self):
        debug_info = pn.widgets.Debugger(
            name="Log",
            level=logging.DEBUG,
            sizing_mode="stretch_both",
            logger_names=["panel.app"],
        )

        param = pn.Param(
            self.param,
            parameters=[
                "extract_button",
                "load_button",
                "progress",
            ],
            widgets={
                "extract_button": {"button_type": "primary"},
                "load_button": {"button_type": "primary"},
            },
        )

        tabs = pn.Tabs(
            ("Tab 1", param),
            ("Tab 2", debug_info),
            dynamic=True,
        )
        return pn.template.MaterialTemplate(
            title="app",
            main=[tabs],
        )

app = Test()
app.init_panel().show()

```

---

<div class="post-metadata">

**Author:** ![Marc](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/marc/32/24_2.png) [@Marc](https://discourse.holoviz.org/u/Marc)\
**Post date:** [March 23, 2024, 5:56am UTC](https://discourse.holoviz.org/t/odd-behavior-when-combining-pn-param-parammethod-and-pn-tabs-dynamic-true/6581/6 "2024-03-23T05:56:44Z")

</div>

Hi @contango

In your example the problem is not `Param`. Instead its the `debug_info`. If I replace `debug_info` with something else like the string `"debug_info"` it works.

```python
import logging

import panel as pn
import param

pn.extension("terminal")

class Test(param.Parameterized):
    load_button = param.Action(label="Load..")
    extract_button = param.Action(label="Extract..")    

    def __init__ (self, **params):
        super(Test, self). __init__ (**params)

    def init_panel(self):
        debug_info = pn.widgets.Debugger(
            name="Log",
            level=logging.DEBUG,
            sizing_mode="stretch_both",
            logger_names=["panel.app"],
        )

        param = pn.Param(
            self.param,
            parameters=[
                "extract_button",
                "load_button",
                "progress",
            ],
            widgets={
                "extract_button": {"button_type": "primary"},
                "load_button": {"button_type": "primary"},
            },
        )

        tabs = pn.Tabs(
            ("Tab 1", param),
            ("Tab 2", "debug_info"),
            dynamic=True,
        )
        return pn.template.MaterialTemplate(
            title="app",
            main=[tabs],
        )

app = Test()
app.init_panel().servable()

```

I’ve reported the issue in [#6546](https://github.com/holoviz/panel/issues/6546)
