Here, I want to grab code from the first tab’s code editor, execute it, and display the results on the second tab, but I don’t want it to execute eagerly until the user clicks on it.
Solution 1
Use pn.param.ParamFunction(func, lazy=True)
alongside pn.Tabs(dynamic=True)
import time
import panel as pn
from panel.io.mime_render import exec_with_return
pn.extension("codeeditor")
async def execute():
print("EXECUTING NOW...")
yield pn.indicators.LoadingSpinner(value=True, align="center", width=50, height=50)
time.sleep(1.28)
result = exec_with_return(code_editor.value)
yield result
code_editor = pn.widgets.CodeEditor(value="'Hello, World!'", language="python")
result = pn.param.ParamFunction(execute, lazy=True)
tabs = pn.Tabs(("Python Code", code_editor), ("Result", result), dynamic=True)
tabs
However, this only runs once meaning if you update the code editor, the second tab will not reflect the new code.
Solution 2
Use pn.bind
and key on active
, with a cache if you want more efficiency.
import time
import panel as pn
from panel.io.mime_render import exec_with_return
pn.extension("codeeditor")
def execute(code, active):
if active != 1:
return placeholder_spinner.clone()
if code in pn.state.cache:
result = pn.state.cache[code]
else:
time.sleep(1.28) # Simulate a long running computation
result = pn.state.cache[code] = exec_with_return(code)
return result
code_editor = pn.widgets.CodeEditor(value="'Hello, World!'", language="python")
placeholder_spinner = pn.indicators.LoadingSpinner(
value=True, align="center", width=50, height=50
)
result = pn.Column()
tabs = pn.Tabs(("Python Code", code_editor), ("Result", result))
result.objects = [pn.bind(execute, code_editor.param.value, tabs.param.active)]
tabs
Now if you update the code, the second tab will also update accordingly!
Credits to Philipp for explaining this.