Getting this error ValueError: failed to validate Line(id='p1043', ...).line_color: expected either None or a value of type Color

Hello

I am doing some realtime plotting and I ran into a problem. My actual code is far more complex than this but I have an MRE that shows the problem at the bottom of this post. When I run this code and click on the toggle button, I get errors like shown below. I only get this when deployed as a Server app. The odd thing is that the line color does change as I expect, it is just that I get this error which shows up in the browser Console and also the terminal.

What am I doing wrong? Thanks in advance!

Here is the error:

ERROR:bokeh.server.protocol_handler:error handling message
 message: Message 'PATCH-DOC' content: {'events': [{'kind': 'ModelChanged', 'model': {'id': 'p1043'}, 'attr': 'line_color', 'new': {'type': 'value', 'value': '#CC79A7'}}]}
 error: ValueError("failed to validate Line(id='p1043', ...).line_color: expected either None or a value of type Color, got Value(value='#CC79A7', transform=Unspecified, units=Unspecified)")
Traceback (most recent call last):
  File "/Users/hschilli/miniforge3/envs/openmdao/lib/python3.11/site-packages/bokeh/server/protocol_handler.py", line 94, in handle
    work = await handler(message, connection)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/hschilli/miniforge3/envs/openmdao/lib/python3.11/site-packages/bokeh/server/session.py", line 94, in _needs_document_lock_wrapper
    result = func(self, *args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/hschilli/miniforge3/envs/openmdao/lib/python3.11/site-packages/bokeh/server/session.py", line 286, in _handle_patch
    message.apply_to_document(self.document, self)
  File "/Users/hschilli/miniforge3/envs/openmdao/lib/python3.11/site-packages/bokeh/protocol/messages/patch_doc.py", line 104, in apply_to_document
    invoke_with_curdoc(doc, lambda: doc.apply_json_patch(self.payload, setter=setter))
  File "/Users/hschilli/miniforge3/envs/openmdao/lib/python3.11/site-packages/bokeh/document/callbacks.py", line 453, in invoke_with_curdoc
    return f()
           ^^^
  File "/Users/hschilli/miniforge3/envs/openmdao/lib/python3.11/site-packages/bokeh/protocol/messages/patch_doc.py", line 104, in <lambda>
    invoke_with_curdoc(doc, lambda: doc.apply_json_patch(self.payload, setter=setter))
                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/hschilli/miniforge3/envs/openmdao/lib/python3.11/site-packages/bokeh/document/document.py", line 391, in apply_json_patch
    DocumentPatchedEvent.handle_event(self, event, setter)
  File "/Users/hschilli/miniforge3/envs/openmdao/lib/python3.11/site-packages/bokeh/document/events.py", line 244, in handle_event
    event_cls._handle_event(doc, event)
  File "/Users/hschilli/miniforge3/envs/openmdao/lib/python3.11/site-packages/bokeh/document/events.py", line 376, in _handle_event
    model.set_from_json(attr, value, setter=event.setter)
  File "/Users/hschilli/miniforge3/envs/openmdao/lib/python3.11/site-packages/bokeh/core/has_props.py", line 448, in set_from_json
    descriptor.set_from_json(self, value, setter=setter)
  File "/Users/hschilli/miniforge3/envs/openmdao/lib/python3.11/site-packages/bokeh/core/property/descriptors.py", line 418, in set_from_json
    value = self.property.prepare_value(obj, self.name, value)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/hschilli/miniforge3/envs/openmdao/lib/python3.11/site-packages/bokeh/core/property/bases.py", line 363, in prepare_value
    raise ValueError(f"failed to validate {obj_repr}.{name}: {error}")
ValueError: failed to validate Line(id='p1043', ...).line_color: expected either None or a value of type Color, got Value(value='#CC79A7', transform=Unspecified, units=Unspecified)

Here is the code:

from bokeh.models import ColumnDataSource, Toggle, Row, CustomJS, SingleIntervalTicker
from bokeh.plotting import figure
from bokeh.server.server import Server
from bokeh.application.application import Application
from bokeh.application.handlers import FunctionHandler
import numpy as np

_time_between_callbacks_in_ms = 1000
varname = "distance"

class RealTimeOptPlot(object):
    def __init__(self, callback_period, doc):

        self.iteration = 0

        p = figure(title=f"Real-time Optimization Progress Plot")
        p.xaxis.ticker = SingleIntervalTicker(interval=1)

        _source_dict = {"iteration": []}
        _source_dict[varname] = []
        self._source = ColumnDataSource(_source_dict)

        line = p.line(
            x='iteration',
            y=varname,
            visible=True,
            color='black',
            source=self._source,
        )

        toggle = Toggle(
            label=varname,
            active=False,
        )

        callback_code=f"""
        line.glyph.line_color = '#CC79A7';
        """
        legend_item_callback = CustomJS(
            args=dict(line=line),
            code=callback_code,
        )
        toggle.js_on_change("active", legend_item_callback)

        def update():
            source_stream_dict = {"iteration": [self.iteration]}
            x = self.iteration
            y = np.sin(x) * np.exp(-0.1 * x)
            source_stream_dict[varname] = [y]

            self.iteration += 1
            self._source.stream(source_stream_dict)

        doc.add_periodic_callback(update, callback_period)
        graph = Row(p, toggle, sizing_mode="stretch_both")
        doc.add_root(graph)

def _make_realtime_opt_plot_doc(doc):
    RealTimeOptPlot(_time_between_callbacks_in_ms, doc=doc)

_port_number = 5000
try:
    server = Server(
        {"/": Application(FunctionHandler(_make_realtime_opt_plot_doc))},
        port=_port_number,
    )
    server.start()
    server.io_loop.add_callback(server.show, "/")

    print(f"Bokeh server running on http://localhost:{_port_number}")
    server.io_loop.start()
except KeyboardInterrupt as e:
    print(f"Server stopped due to keyboard interrupt")
except Exception as e:
    print(f"Error starting Bokeh server: {e}")
finally:
    print("Stopping server")
    if "server" in globals():
        server.stop()

@herbcle This seems like a bug, please open a GitHub Issue. It’s possible we can suggest a short-term WAR in the issue.

Submitted! Thanks

1 Like

I know you are super busy, but a short-term WAR would be great. I have many internal customers waiting for the plot I am creating. Thanks.

@herbcle I’d suggest asking on the issue, there are more core devs that will it there.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.