Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ReactiveHTML: too much recursion error #2928

Closed
MarcSkovMadsen opened this issue Nov 18, 2021 · 8 comments · Fixed by #2935
Closed

ReactiveHTML: too much recursion error #2928

MarcSkovMadsen opened this issue Nov 18, 2021 · 8 comments · Fixed by #2935
Milestone

Comments

@MarcSkovMadsen
Copy link
Collaborator

Panel: 0.12.4

I'm trying to create a component using ReactiveHTML. But when I display it together with its .controls I get a too much recursion error in the client.

Does not work

too-much-recursion.mp4
import random

import panel as pn
import param

pn.extension(sizing_mode="stretch_width")

def dummy_model():
    val = float(random.randint(0, 100)) / 100
    return [
            {"label": "Egyptian cat", "score": val * 5 / 15},
            {"label": "tabby, tabby cat", "score": val * 4 / 15},
        ]
class ClassificationPlot(pn.reactive.ReactiveHTML):
    output_json = param.List()
    _template = """<div id="component"></div>"""
    _scripts = {
        "output_json": """console.log("x")""",
    }

plot = ClassificationPlot(output_json=dummy_model())

run_button = pn.widgets.Button(name="Run Classification", button_type="primary")
def run_classification(_):
    plot.output_json=dummy_model()
run_button.on_click(run_classification)

pn.Column(run_button, plot, plot.controls()).servable()
@MarcSkovMadsen MarcSkovMadsen added the TRIAGE Default label for untriaged issues label Nov 18, 2021
@MarcSkovMadsen
Copy link
Collaborator Author

MarcSkovMadsen commented Nov 18, 2021

It Works If I return a list of length 1 instead of 2 in dummy_model.

But that is of course not what I want.

works-list-len-1.mp4
import random

import panel as pn
import param

pn.extension(sizing_mode="stretch_width")

def dummy_model():
    val = float(random.randint(0, 100)) / 100
    return [
            {"label": "Egyptian cat", "score": val * 5 / 15},
            # {"label": "tabby, tabby cat", "score": val * 4 / 15},
        ]
class ClassificationPlot(pn.reactive.ReactiveHTML):
    output_json = param.List()
    _template = """<div id="component"></div>"""
    _scripts = {
        "output_json": """console.log("x")""",
    }

plot = ClassificationPlot(output_json=dummy_model())

run_button = pn.widgets.Button(name="Run Classification", button_type="primary")
def run_classification(_):
    plot.output_json=dummy_model()
run_button.on_click(run_classification)

pn.Column(run_button, plot, plot.controls()).servable()

@MarcSkovMadsen
Copy link
Collaborator Author

MarcSkovMadsen commented Nov 18, 2021

It Works If I remove the plot.controls()

But that is of course not what I want.

works-without-plot-control.mp4
import random

import panel as pn
import param

pn.extension(sizing_mode="stretch_width")

def dummy_model():
    val = float(random.randint(0, 100)) / 100
    return [
            {"label": "Egyptian cat", "score": val * 5 / 15},
            {"label": "tabby, tabby cat", "score": val * 4 / 15},
        ]
class ClassificationPlot(pn.reactive.ReactiveHTML):
    output_json = param.List()
    _template = """<div id="component"></div>"""
    _scripts = {
        "output_json": """console.log("x")""",
    }

plot = ClassificationPlot(output_json=dummy_model())

run_button = pn.widgets.Button(name="Run Classification", button_type="primary")
def run_classification(_):
    plot.output_json=dummy_model()
run_button.on_click(run_classification)

pn.Column(run_button, plot, ).servable() # plot.controls()

@MarcSkovMadsen MarcSkovMadsen added type: bug and removed TRIAGE Default label for untriaged issues labels Nov 18, 2021
@MarcSkovMadsen MarcSkovMadsen added this to the v0.13.0 milestone Nov 18, 2021
@MarcSkovMadsen
Copy link
Collaborator Author

MarcSkovMadsen commented Nov 18, 2021

Workaround - Set jslink=False

works-if-js-link-false.mp4
import random

import panel as pn
import param

pn.extension(sizing_mode="stretch_width")

def dummy_model():
    val = float(random.randint(0, 100)) / 100
    return [
            {"label": "Egyptian cat", "score": val * 5 / 15},
            {"label": "tabby, tabby cat", "score": val * 4 / 15},
        ]
class ClassificationPlot(pn.reactive.ReactiveHTML):
    output_json = param.List()
    data = param.List(constant=True)
    _template = """<div id="component"></div>"""
    _scripts = {
        "output_json": """console.log("x")""",
    }

plot = ClassificationPlot(output_json=dummy_model())

run_button = pn.widgets.Button(name="Run Classification", button_type="primary")
def run_classification(_):
    with param.edit_constant(plot):
        plot.output_json=[dummy_model()]
run_button.on_click(run_classification)

pn.Column(run_button, plot, plot.controls(jslink=False)).servable()

@philippjfr
Copy link
Member

This is not really ReactiveHTML's fault. The jslink will link two properties, if the JSON changes even slightly then the event will bounce back and forth between the two models until a recursion error is raised.

@MarcSkovMadsen
Copy link
Collaborator Author

Can it be fixed?

@philippjfr
Copy link
Member

Probably something you have to fix yourself by ensuring that whatever property is being synced and is bouncing back and forth has a consistent representation.

@philippjfr
Copy link
Member

It seems like something is inserting additional spaces after the comma in this string "tabby, tabby cat". Will have to look at what's doing that.

@philippjfr
Copy link
Member

Found the issue, it's the target_transform on LiteralInput, fix incoming.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants