holoviz / panel

Panel: The powerful data exploration & web app framework for Python
https://panel.holoviz.org
BSD 3-Clause "New" or "Revised" License
4.77k stars 519 forks source link

RangeXY raising exception with panel serve but not in Notebook #883

Closed MarcSkovMadsen closed 4 years ago

MarcSkovMadsen commented 4 years ago

Hi

I'm trying to make a reactive dashboard. I now have my dashboard working great in a Jupyter Notebook. But when I run it via 'panel serve' it raises the below 'exception'.

Maybe it's me that misunderstands something. I've tried many different ways of implementing this as cannot find a reference example.

$ python -m panel serve 'src\pages\gallery\kickstarter_dashboard\main.py' --dev --show
C:\repos\private\awesome-panel\.venv\lib\site-packages\bokeh\command\util.py:127: UserWarning:
It looks like you might be running the main.py of a directory app directly.
If this is the case, to enable the features of directory style apps, you must
call "bokeh serve" on the directory instead. For example:

    bokeh serve my_app_dir/

If this is not the case, renaming main.py will suppress this warning.

  warnings.warn(DIRSTYLE_MAIN_WARNING)
2019-12-18 12:20:25,354 Starting Bokeh server version 1.4.0 (running on Tornado 5.1.1)
2019-12-18 12:20:25,356 User authentication hooks NOT provided (default user enabled)
2019-12-18 12:20:25,361 Bokeh app running at: http://localhost:5006/main
2019-12-18 12:20:25,362 Starting Bokeh server with process id: 8752
2019-12-18 12:20:31,342 WebSocket connection opened
2019-12-18 12:20:31,344 ServerConnection created
C:\repos\private\awesome-panel\src\pages\gallery\kickstarter_dashboard\main.py:208: UserWarning: Boolean Series key will be reindexed to match DataFrame index.
  sub_df = sub_df[x_filter]
WARNING:param.ParamMethod01391: HoloViews pane model Figure(id='1371', ...) could not be replaced with new model Figure(id='1819', ...), ensure that the parent is not modified at the same time the panel is being updated.
2019-12-18 12:20:36,987 HoloViews pane model Figure(id='1371', ...) could not be replaced with new model Figure(id='1819', ...), ensure that the parent is not modified at the same time the panel is being updated.
2019-12-18 12:20:37,347 Exception in callback functools.partial(<function wrap.<locals>.null_wrapper at 0x0000005386226C18>,
<Future finished exception=TypeError("Constant parameter 'x_range' cannot be modified")>)
Traceback (most recent call last):
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\tornado\ioloop.py", line 758, in _run_callback
    ret = callback()
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\tornado\stack_context.py", line 300, in null_wrapper
    return fn(*args, **kwargs)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\tornado\ioloop.py", line 779, in _discard_future_result
    future.result()
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\tornado\gen.py", line 1147, in run
    yielded = self.gen.send(value)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\bokeh\server\session.py", line 70, in _needs_document_lock_wrapper
    result = yield yield_for_all_futures(func(self, *args, **kwargs))
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\bokeh\server\session.py", line 191, in with_document_locked
    return func(*args, **kwargs)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\bokeh\document\document.py", line 1127, in wrapper
    return doc._with_self_as_curdoc(invoke)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\bokeh\document\document.py", line 1113, in _with_self_as_curdoc
    return f()
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\bokeh\document\document.py", line 1126, in invoke
    return f(*args, **kwargs)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\bokeh\document\document.py", line 916, in remove_then_invoke
    return callback(*args, **kwargs)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\panel\viewable.py", line 714, in _change_event
    self._process_events(events)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\panel\viewable.py", line 704, in _process_events
    self.set_param(**self._process_property_change(events))
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\param\parameterized.py", line 1219, in inner
    return fn(*args, **kwargs)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\param\parameterized.py", line 2573, in set_param
    return self_or_cls.param.set_param(*args,**kwargs)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\param\parameterized.py", line 1365, in set_param
    self_._batch_call_watchers()
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\param\parameterized.py", line 1480, in _batch_call_watchers
    watcher.fn(*events)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\panel\param.py", line 345, in link_widget
    self.object.set_param(**{p_name: change.new})
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\param\parameterized.py", line 1219, in inner
    return fn(*args, **kwargs)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\param\parameterized.py", line 2573, in set_param
    return self_or_cls.param.set_param(*args,**kwargs)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\param\parameterized.py", line 1358, in set_param
    setattr(self_or_cls, k, v)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\param\parameterized.py", line 294, in _f
    instance_param.__set__(obj, val)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\param\parameterized.py", line 296, in _f
    return f(self, obj, val)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\param\parameterized.py", line 838, in __set__
    raise TypeError("Constant parameter '%s' cannot be modified"%self.name)
TypeError: Constant parameter 'x_range' cannot be modified
C:\repos\private\awesome-panel\src\pages\gallery\kickstarter_dashboard\main.py:208: UserWarning: Boolean Series key will be reindexed to match DataFrame index.
  sub_df = sub_df[x_filter]
WARNING:param.ParamMethod01391: HoloViews pane model Figure(id='1819', ...) could not be replaced with new model Figure(id='1976', ...), ensure that the parent is not modified at the same time the panel is being updated.
2019-12-18 12:20:37,858 HoloViews pane model Figure(id='1819', ...) could not be replaced with new model Figure(id='1976', ...), ensure that the parent is not modified at the same time the panel is being updated.
WARNING:param.ParamMethod01391: HoloViews pane model Figure(id='1819', ...) could not be replaced with new model Figure(id='2072', ...), ensure that the parent is not modified at the same time the panel is being updated.
2019-12-18 12:20:37,940 HoloViews pane model Figure(id='1819', ...) could not be replaced with new model Figure(id='2072', ...), ensure that the parent is not modified at the same time the panel is being updated.
2019-12-18 12:20:38,271 Exception in callback functools.partial(<function wrap.<locals>.null_wrapper at 0x0000005386226EE8>,
<Future finished exception=TypeError("Constant parameter 'x_range' cannot be modified")>)
Traceback (most recent call last):
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\tornado\ioloop.py", line 758, in _run_callback
    ret = callback()
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\tornado\stack_context.py", line 300, in null_wrapper
    return fn(*args, **kwargs)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\tornado\ioloop.py", line 779, in _discard_future_result
    future.result()
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\tornado\gen.py", line 1147, in run
    yielded = self.gen.send(value)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\bokeh\server\session.py", line 70, in _needs_document_lock_wrapper
    result = yield yield_for_all_futures(func(self, *args, **kwargs))
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\bokeh\server\session.py", line 191, in with_document_locked
    return func(*args, **kwargs)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\bokeh\document\document.py", line 1127, in wrapper
    return doc._with_self_as_curdoc(invoke)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\bokeh\document\document.py", line 1113, in _with_self_as_curdoc
    return f()
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\bokeh\document\document.py", line 1126, in invoke
    return f(*args, **kwargs)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\bokeh\document\document.py", line 916, in remove_then_invoke
    return callback(*args, **kwargs)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\panel\viewable.py", line 714, in _change_event
    self._process_events(events)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\panel\viewable.py", line 704, in _process_events
    self.set_param(**self._process_property_change(events))
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\param\parameterized.py", line 1219, in inner
    return fn(*args, **kwargs)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\param\parameterized.py", line 2573, in set_param
    return self_or_cls.param.set_param(*args,**kwargs)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\param\parameterized.py", line 1365, in set_param
    self_._batch_call_watchers()
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\param\parameterized.py", line 1480, in _batch_call_watchers
    watcher.fn(*events)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\panel\param.py", line 345, in link_widget
    self.object.set_param(**{p_name: change.new})
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\param\parameterized.py", line 1219, in inner
    return fn(*args, **kwargs)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\param\parameterized.py", line 2573, in set_param
    return self_or_cls.param.set_param(*args,**kwargs)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\param\parameterized.py", line 1358, in set_param
    setattr(self_or_cls, k, v)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\param\parameterized.py", line 294, in _f
    instance_param.__set__(obj, val)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\param\parameterized.py", line 296, in _f
    return f(self, obj, val)
  File "C:\repos\private\awesome-panel\.venv\lib\site-packages\param\parameterized.py", line 838, in __set__
    raise TypeError("Constant parameter '%s' cannot be modified"%self.name)
TypeError: Constant parameter 'x_range' cannot be modified

Interrupted, shutting down
(.venv)

I've attached the source code, notebook and data.

issue_rangexy.zip

and a small video that shows it works fine in the notebook. But when you start interacting with panel serve it raises the exception.

note_book_works

MarcSkovMadsen commented 4 years ago

Moved to https://github.com/holoviz/panel/issues/882

philippjfr commented 4 years ago

I'd moved it to HoloViews on purpose.

MarcSkovMadsen commented 4 years ago

Ahh. I just saw that. Sorry.

MarcSkovMadsen commented 4 years ago

I thought it was me being tired after all those efforts getting rangeXY working. So I thought I posted in wrong Repo.

philippjfr commented 4 years ago

A bit more detail on what your example looks like would be very helpful.

philippjfr commented 4 years ago

Ah sorry, I see you posted the file, sorry about that.

philippjfr commented 4 years ago

I see the issue, you are trying to create a widget from the RangeXY stream, is that intentional? Streams cannot currently be used that way, but I suppose we could change that.

MarcSkovMadsen commented 4 years ago

Hi @philippjfr . The problem is I cannot find a reference example of how develop a reactive dashboard in Panel with

based on a parametrized class. All the examples only have the individual parts. So I don't know how they can work together. But I'm trying to make it work. But it's guess work.

How would I make rangeXY work? And why does it work in a notebook and not with panel serve? If it works in the notebook it's natural to me think think i have a correct implementation.

Could you give me some kind of hint on how to solve this. I've spent maybe 8 hours now trying to get it working.

I think the next step for me would be to systematic go though the different tutorials of HoloViews, hvplot, streams, param and panel. Because I need to know them all in order to work efficiently with Panel. I just started out skimming the Panel docs, developing a bit, reading some more Panel docs and what I needed of the rest.

But there is actually a lot of concepts to understand and master before you can get things to work together. And how the different things work together is not yet that obvious to me. For example I have a feeling that I could implement a dashboard in HoloViews alone with a rangeXY stream. I could also develop it in Panel. But the two ways are different. So when I read the documentation of both I'm not yet cabable of understanding how things should be done the Panel way.

And I have a feeling that when I have this working I have the reference example of how all my dashboards would be implemented. They would just be variations of this with maybe more widgets, streams and plots/ tables in some cases.

Thanks

philippjfr commented 4 years ago

Okay this turns out not be your fault at all. It's a bug in Panel afterall. Just a quick tip though, you are declaring rangexy as a class attribute:

rangexy = hv.streams.RangeXY()

This isn't ideal because if you serve the app to multiple people they'll all share the same instance of RangeXY. I'd replace that with:

rangexy = param.ClassSelector(class_=hv.streams.RangeXY, default=hv.streams.RangeXY())

I'll push a fix for the bug in a second though.

philippjfr commented 4 years ago

Actually there also is a second issue, you are returning the x_range as part of the layout:

return pn.Column(
            __doc__,
            self.param.categories,
            self.scatter_plot_view,
            self.bar_chart_view,
            self.rangexy,
            sizing_mode="stretch_width",
        )

This is problematic on the server because it ends up syncing the widget state back to Python and tries to edit the parameter. We need to make sure that it never tries to set stream parameter values.

MarcSkovMadsen commented 4 years ago

Okay this turns out not be your fault at all. It's a bug in Panel afterall. Just a quick tip though, you are declaring rangexy as a class attribute:

rangexy = hv.streams.RangeXY()

This isn't ideal because if you serve the app to multiple people they'll all share the same instance of RangeXY. I'd replace that with:

rangexy = param.ClassSelector(class_=hv.streams.RangeXY, default=hv.streams.RangeXY())

I'll push a fix for the bug in a second though.

Thanks. Thats a level of detail I had not grasped. I guess I forgot because I have been working with Streamlit lately and there the python script is run on each change and not once by the server.

I actually thought the script was read/ evaluated once for each session. Now I learned its not.

And i'm so happy it was not my fault :-)

MarcSkovMadsen commented 4 years ago

Actually there also is a second issue, you are returning the x_range as part of the layout:

return pn.Column(
            __doc__,
            self.param.categories,
            self.scatter_plot_view,
            self.bar_chart_view,
            self.rangexy,
            sizing_mode="stretch_width",
        )

This is problematic on the server because it ends up syncing the widget state back to Python and tries to edit the parameter. We need to make sure that it never tries to set stream parameter values.

Thanks. It was only there for testing purposes right now. Is should not be in there for the final version.

philippjfr commented 4 years ago

Thanks. Thats a level of detail I had not grasped. I guess I forgot because I have been working with Streamlit lately and there the python script is run on each change and not once by the server.

Actually I'm wrong about that if you run it with panel serve or bokeh serve it is indeed reevaluated.

philippjfr commented 4 years ago

Fixed in https://github.com/holoviz/panel/pull/884.

MarcSkovMadsen commented 4 years ago

@philippjfr . I've tested the new master and it works and the rangeXY works and no exceptions are raised.

But just for your info. The log shows entries like

2019-12-18 19:20:40,377 Cannot apply patch to 3107 which is not in the document anymore

You've previously told me I should just ignore them. So I will.

Thanks for the help.

philippjfr commented 4 years ago

I really wish I could do something about those warnings easily. They are indeed totally harmless but somewhat disconcerting nonetheless.