# Bug with DeserializationError when changing content layout in Bokeh 3.1.1

**URL:** <https://discourse.bokeh.org/t/bug-with-deserializationerror-when-changing-content-layout-in-bokeh-3-1-1/10566>\
**Category:** Community Support\
**Created:** [June 19, 2023, 1:40pm UTC](https://discourse.bokeh.org/t/bug-with-deserializationerror-when-changing-content-layout-in-bokeh-3-1-1/10566 "2023-06-19T13:40:17Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Aziuth](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/aziuth/32/6060_2.png) [@Aziuth](https://discourse.bokeh.org/u/Aziuth)\
**Post date:** [June 19, 2023, 1:40pm UTC](https://discourse.bokeh.org/t/bug-with-deserializationerror-when-changing-content-layout-in-bokeh-3-1-1/10566/1 "2023-06-19T13:40:17Z")

</div>

This is a copy of my post on SO: [python - Bokeh 3.1.1 DeserializationError when changing layout content - Stack Overflow](https://stackoverflow.com/questions/76506289/bokeh-3-1-1-deserializationerror-when-changing-layout-content)

I have a project that worked fine under Bokeh 2.4.3 but after me upgrading to 3.1.1 produces `bokeh.core.serialization.DeserializationError`s.

The culprit is me having frames which first display a “loading screen” and afterwards an actual plot.  
I have a class that manages a frame and looks somewhat like this, simplified:

```auto
class MyFrame:

    def __init__ (self):
        self.layout = column()
        self.loading = loading_pic()
        self.layout.children.append(self.loading)

    def display_loading(self) -> None:
        self.layout.children[0] = self.loading

    def plot(self, data) -> None:
        self.my_plot = MyPlot(data)
        self.layout.children[0] = self.my_plot 

```

In this, the function `loading_pic()` simply generates a (Bokeh) plot that contains the label “Loading”, while the `MyPlot` class does some more sophisticated rendering.

This produces the error

```auto
2023-06-19 13:29:44,116 error handling message
 message: Message 'PATCH-DOC' content: {'events': [{'kind': 'ModelChanged', 'model': {'id': 'p1004'}, 'attr': 'inner_width', 'new': 865}, {'kind': 'ModelChanged', 'model': {'id': 'p1004'}, 'attr': 'inner_height', 'new': 540}, {'kind': 'ModelChanged', 'model': {'id': 'p1004'}, 'attr': 'outer_width', 'new': 900}, {'kind': 'ModelChanged', 'model': {'id': 'p1004'}, 'attr': 'outer_height', 'new': 550}]}
 error: DeserializationError("can't resolve reference 'p1004'")

```

Reference p1004 is the loading screen, and if I turn the code of `display_loading` into a comment, the error goes away (but of course so does the loading screen functionality).  
Interestingly by my code as is, the loading screen plot object exists during the error, and also the loading screen is still actually used in the ` __init__ ` method. And I actually see the loading screen during the initial loadup.

Now the error does not crash the program and it actually works despite it, but leaving it as is, suppressing it, or not using loading screens all feel like code smell to me.

Does anybody have an idea what causes this? Is Bokeh trying to resize an item that is not visible?

---

<div class="post-metadata">

**Author:** ![Bryan](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/bryan/32/3625_2.png) [@Bryan](https://discourse.bokeh.org/u/Bryan)\
**Post date:** [June 19, 2023, 2:00pm UTC](https://discourse.bokeh.org/t/bug-with-deserializationerror-when-changing-content-layout-in-bokeh-3-1-1/10566/2 "2023-06-19T14:00:10Z")

</div>

@Aziuth it is impossible to speculate without a complete [Minimal Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) to actually run and investigate.

---

<div class="post-metadata">

**Author:** ![Aziuth](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/aziuth/32/6060_2.png) [@Aziuth](https://discourse.bokeh.org/u/Aziuth)\
**Post date:** [June 19, 2023, 2:32pm UTC](https://discourse.bokeh.org/t/bug-with-deserializationerror-when-changing-content-layout-in-bokeh-3-1-1/10566/3 "2023-06-19T14:32:10Z")

</div>

Took me a while to assemble one, given that my actual code is a big bulk, but here it is.  
Supposed to be executed as a Bokeh server.

To produce the bug, change the value of the range slider _twice_.

```auto
from bokeh.plotting import figure, curdoc
from bokeh.models import ColumnDataSource, Label, RangeSlider
from bokeh.layouts import column
from random import *

def loading_pic(width: int = 500, height: int = 500) -> figure:
    plot = figure(x_range=(0,width), y_range=(0,height), width=width, height=height, tools='')
    pos_x = width/2 
    pos_y = height/2    
    
    label_size = min(height/4, width/4)
    label_size_str = str(label_size)+'px'
    
    loading_label = Label(x=pos_x, y=pos_y, text='Loading', text_font_size = label_size_str,
                          text_align='center', text_baseline='middle')
    plot.add_layout(loading_label)
    
    plot.xaxis.visible = False
    plot.yaxis.visible = False
    plot.xgrid.grid_line_color = None
    plot.ygrid.grid_line_color = None
    
    return plot
    
def random_coords(maximum: float = 500, amount: int = 1000) -> ColumnDataSource:
    data = ColumnDataSource()
    data.data['x'] = [random()*maximum for i in range(amount)]
    data.data['y'] = [random()*maximum for i in range(amount)]
    return data
    
class MyPlot:
    
    def __init__ (self, data: ColumnDataSource):
        self.plot = figure(x_range=(0,500), y_range=(0,500), width=500, height=500)
        self.plot.circle(source=data, x='x', y='y')
    
class MyFrame:

    def __init__ (self):
        self.layout = column()
        self.loading = loading_pic()
        self.layout.children.append(self.loading)

    def display_loading(self) -> None:
        self.layout.children[0] = self.loading

    def plot(self, data) -> None:
        self.my_plot = MyPlot(data)
        self.layout.children[0] = self.my_plot.plot
        
    def plot_delayed(self, attr, old, new) -> None:
        self.display_loading()
        data = random_coords()
        curdoc().add_next_tick_callback(lambda: self.plot(data)) 
        
my_frame = MyFrame()
        
range_slider = RangeSlider(start = 0, end = 10, value = (0,10), step = 1, title = 'Range')
range_slider.on_change('value_throttled', my_frame.plot_delayed)
       
layout = column(my_frame.layout, range_slider)

curdoc().add_root(layout)

```

---

<div class="post-metadata">

**Author:** ![Bryan](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/bryan/32/3625_2.png) [@Bryan](https://discourse.bokeh.org/u/Bryan)\
**Post date:** [June 20, 2023, 3:32am UTC](https://discourse.bokeh.org/t/bug-with-deserializationerror-when-changing-content-layout-in-bokeh-3-1-1/10566/4 "2023-06-20T03:32:19Z")

</div>

@Aziuth FWIW this message was changed recently. Here is how it will appear in 3.2

> 2023-06-19 20:26:49,756 Dropping a patch because it contains a previously known reference (id=‘p1002’). Most of the time this is harmless and usually a result of updating a model on one side of a communications channel while it was being removed on the other end.

We display this message for “completeness” sake, but it’s actually not usually anything to be concerned with. So to be honest, I think you are worrying more than you need to be, and can just forget about it.

If you really want to get rid of it, though, your best bet is to add both plots to the layout up front an then toggle their visibility rather than removing/replacing them in the layout.

---

<div class="post-metadata">

**Author:** ![Aziuth](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/aziuth/32/6060_2.png) [@Aziuth](https://discourse.bokeh.org/u/Aziuth)\
**Post date:** [June 20, 2023, 9:47am UTC](https://discourse.bokeh.org/t/bug-with-deserializationerror-when-changing-content-layout-in-bokeh-3-1-1/10566/5 "2023-06-20T09:47:07Z")

</div>

Yeah, I kinda thought so, but I am always hesitant to ignore warnings.

I guess I will suppress the error type since I need to be able to read the rest of the output and this one kinda spams the log.  
Probably won’t go with the invisibility variant, as I think that would make my code less readable - I’d have to add an explanation why I do it that way.

Thanks for the answer.

---

<div class="post-metadata">

**Author:** ![Aziuth](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/aziuth/32/6060_2.png) [@Aziuth](https://discourse.bokeh.org/u/Aziuth)\
**Post date:** [June 20, 2023, 12:29pm UTC](https://discourse.bokeh.org/t/bug-with-deserializationerror-when-changing-content-layout-in-bokeh-3-1-1/10566/6 "2023-06-20T12:29:34Z")

</div>

Now, I _said_ that I’m going to suppress the error, but how to do so? I know how to silence _warnings_ in python, but I’m not sure how to do that with errors. Putting a huge try-catch around ther whole program doesn’t sound like the right way to go.

---

<div class="post-metadata">

**Author:** ![Bryan](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/bryan/32/3625_2.png) [@Bryan](https://discourse.bokeh.org/u/Bryan)\
**Post date:** [June 20, 2023, 3:04pm UTC](https://discourse.bokeh.org/t/bug-with-deserializationerror-when-changing-content-layout-in-bokeh-3-1-1/10566/7 "2023-06-20T15:04:29Z")

</div>

> [@Aziuth](#):
>
> Probably won’t go with the invisibility variant, as I think that would make my code less readable - I’d have to add an explanation why I do it that way.

This is certainly a matter of opinion and style. Personally I find setting a `visible` property to be a self-documenting action that states something should be shown or hidden from the user.

I would also be remiss if I don’t remind that the express purpose of the Bokeh server is to automatically synchronize a document state over the network. By making a “big” change, e.g. adding and removing entire plots from the layout, you will cause the plots, all their sub-components (including data sources and all their data) to be serialized, trasnsmitted over the network, deserialized, and initialized— on every single slider movement. This is the Bokeh server performing exactly as designed and intended By contrast, setting the `visible` property only results in a very small update to toggle the value of an existing property.

FWIW the consistent best practice we have always demonstrated and stated is “make the smallest change possible”.

> Now, I _said_ that I’m going to suppress the error, but how to do so?

This isn’t an exception that is surfaced to you. It’s an exception that is caught internally and logged informationally. I don’t actually have any suggestions for you here, except to lower the log level.

---

<div class="post-metadata">

**Author:** ![Aziuth](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/aziuth/32/6060_2.png) [@Aziuth](https://discourse.bokeh.org/u/Aziuth)\
**Post date:** [June 22, 2023, 12:35pm UTC](https://discourse.bokeh.org/t/bug-with-deserializationerror-when-changing-content-layout-in-bokeh-3-1-1/10566/8 "2023-06-22T12:35:43Z")

</div>

I took your advice and used an invisibility approach.

However, now I am facing the next wave of the same error, but this time for the actual plot. The error is now triggered when the actual plot is exchanged for an entirely new one.

I could try to change the source of the old plot, but that feels strange. And also error-prone - a completely new plot contains only the elements it should, a modified old plot might contain artifacts from the old one, old settings or old elements.

Below code to trigger the bug, again by changing the slider twice. I added a debug output that shows the ID of the created plot, having us clearly see that the last actual plot is the culprit reference.

Also note that despite me now using `hold` and `unhold` like you suggested to me in another thread, the invisibility approach causes a hickup, showing both the loading screen and the plot at once for a split second.  
If I reverse the visibility assignments, one sees none for a split second, trading a “down” hickup for an “up” hickup. That’s a bit suboptimal - am I doing something wrong here? Or is `hold` only working for actual plots, but not layouts? In a different place where I use the arrows from the other thread, `hold` works fine.

```auto
from bokeh.plotting import figure, curdoc
from bokeh.models import ColumnDataSource, Label, RangeSlider
from bokeh.layouts import column
from random import *

def loading_pic(width: int = 500, height: int = 500) -> figure:
    plot = figure(x_range=(0,width), y_range=(0,height), width=width, height=height, tools='')
    pos_x = width/2 
    pos_y = height/2    
    
    label_size = min(height/4, width/4)
    label_size_str = str(label_size)+'px'
    
    loading_label = Label(x=pos_x, y=pos_y, text='Loading', text_font_size = label_size_str,
                          text_align='center', text_baseline='middle')
    plot.add_layout(loading_label)
    
    plot.xaxis.visible = False
    plot.yaxis.visible = False
    plot.xgrid.grid_line_color = None
    plot.ygrid.grid_line_color = None
    
    return plot
    
def random_coords(maximum: float = 500, amount: int = 10000) -> ColumnDataSource:
    data = ColumnDataSource()
    data.data['x'] = [random()*maximum for i in range(amount)]
    data.data['y'] = [random()*maximum for i in range(amount)]
    return data
    
class MyPlot:
    
    def __init__ (self, data: ColumnDataSource):
        self.plot = figure(x_range=(0,500), y_range=(0,500), width=500, height=500)
        self.plot.circle(source=data, x='x', y='y')
    
class MyFrame:

    def __init__ (self):

        self._loading = loading_pic()

        self._loading_container = column(self._loading)
        self._render_container = column(column())
        self._render_container.visible = False
        
        self.layout = column(self._loading_container, self._render_container)

    def display_loading(self) -> None:
        curdoc().hold("combine")
        self._loading_container.visible = True
        self._render_container.visible = False
        curdoc().unhold()

    def plot(self) -> None:
        curdoc().hold("combine")
        data = random_coords()
        self._my_plot = MyPlot(data)
        print("plot:", self._my_plot.plot)
        self._render_container.children[0] = self._my_plot.plot
        self._loading_container.visible = False
        self._render_container.visible = True
        curdoc().unhold()
        
    def plot_delayed(self, attr, old, new) -> None:
        self.display_loading()
        curdoc().add_next_tick_callback(self.plot) 
        
my_frame = MyFrame()
        
range_slider = RangeSlider(start = 0, end = 10, value = (0,10), step = 1, title = 'Range')
range_slider.on_change('value_throttled', my_frame.plot_delayed)
       
layout = column(my_frame.layout, range_slider)

curdoc().add_root(layout)

```

---

<div class="post-metadata">

**Author:** ![Bryan](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/bryan/32/3625_2.png) [@Bryan](https://discourse.bokeh.org/u/Bryan)\
**Post date:** [June 22, 2023, 3:44pm UTC](https://discourse.bokeh.org/t/bug-with-deserializationerror-when-changing-content-layout-in-bokeh-3-1-1/10566/9 "2023-06-22T15:44:38Z")

</div>

> I could try to change the source of the old plot, but that feels strange

Bokeh is expressly geared towards updating data sources. That is the usage that has been heavily optimized and thoroughly tested and understood. Pretty much all of the interactive examples in docs and this forum achieve their results by updating data sources. I can’t make you take my advice, all I can say is: this is how the library is intended to be used, and by not doing so, you are fighting the tool.

> That’s a bit suboptimal - am I doing something wrong here?

No but update events are ultimately processed individually _some order_. There’s probably improvements or new features that could be made here, resources allowing. I’d suggest you make a focused and detailed [GitHub Issue](https://github.com/bokeh/bokeh/issues).

I can tell you how I would solve this using pure Bokeh (put everything in one plot, including the “loading” text, and just update that one plot), but I don’t have the impression you would find it acceptable.

At this point I might actually suggest you [take a look at Panel](https://panel.holoviz.org/index.html), which is built on top of Bokeh, intended for creating more dashboard-y output from a higher level. They also have some corporate resources backing their development, so they can afford to put more effort into some areas. E.g. they have a loading spinner built in: [LoadingSpinner — Panel v1.3.4](https://panel.holoviz.org/reference/indicators/LoadingSpinner.html)

---

<div class="post-metadata">

**Author:** ![Aziuth](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/aziuth/32/6060_2.png) [@Aziuth](https://discourse.bokeh.org/u/Aziuth)\
**Post date:** [June 23, 2023, 11:14am UTC](https://discourse.bokeh.org/t/bug-with-deserializationerror-when-changing-content-layout-in-bokeh-3-1-1/10566/10 "2023-06-23T11:14:42Z")

</div>

Thanks for the advice, I followed it and just created an issue:

> <https://github.com/bokeh/bokeh/issues/13229>
>
> \### Software versions
> 
> Python version : 3.9.16 (main, Mar 8 2023, 10:39…:24) \[MSC v.1916 64 bit (AMD64)\]
> IPython version : 8.12.0
> Tornado version : 6.2
> Bokeh version : 3.1.1
> BokehJS static path : C:\\Users\\\<my username\>\\anaconda3\\lib\\site-packages\\bokeh\\server\\static
> node.js version : (not installed)
> npm version : (not installed)
> Operating system : Windows-10-10.0.22621-SP0
> 
> \### Browser name and version
> 
> Firefox 114.0.2 (64-bit)
> 
> \### Expected behavior
> 
> Within a Bokeh server application, I have a layout in which I render a plot which is to be exchanged when a button is pressed. In between, a loading screen (a plot with just a label that says "Loading") is to be displayed.
> 
> \### Observed behavior
> 
> It works, but each time the exchange is made, it produces an error like
> \`bokeh.core.serialization.DeserializationError: can't resolve reference 'p1074'\`
> with the reference being the last plot.
> 
> \### Example code
> 
> \`\`\`Python
> from bokeh.plotting import figure, curdoc
> from bokeh.models import ColumnDataSource, Label, Button
> from bokeh.layouts import column
> from random import \*
> 
> def loading\_pic(width: int = 500, height: int = 500) -\> figure:
> plot = figure(x\_range=(0,width), y\_range=(0,height), width=width, height=height, tools='')
> pos\_x = width/2 
> pos\_y = height/2    
>     
> label\_size = min(height/4, width/4)
> label\_size\_str = str(label\_size)+'px'
>     
> loading\_label = Label(x=pos\_x, y=pos\_y, text='Loading', text\_font\_size = label\_size\_str,
> text\_align='center', text\_baseline='middle')
> plot.add\_layout(loading\_label)
>     
> plot.xaxis.visible = False
> plot.yaxis.visible = False
> plot.xgrid.grid\_line\_color = None
> plot.ygrid.grid\_line\_color = None
>     
> return plot
>     
> def random\_coords(maximum: float = 500, amount: int = 10000) -\> ColumnDataSource:
> data = ColumnDataSource()
> data.data\['x'\] = \[random()\*maximum for i in range(amount)\]
> data.data\['y'\] = \[random()\*maximum for i in range(amount)\]
> return data
>     
> class MyPlot:
>     
> def \_\_init\_\_(self, data: ColumnDataSource):
> self.plot = figure(x\_range=(0,500), y\_range=(0,500), width=500, height=500)
> self.plot.circle(source=data, x='x', y='y')
>     
> class MyFrame:
> 
> def \_\_init\_\_(self):
> 
> self.\_loading = loading\_pic()
> 
> self.\_loading\_container = column(self.\_loading)
> self.\_render\_container = column(column())
> self.\_render\_container.visible = False
>         
> self.layout = column(self.\_loading\_container, self.\_render\_container)
> 
> def display\_loading(self) -\> None:
> curdoc().hold("combine")
> self.\_loading\_container.visible = True
> self.\_render\_container.visible = False
> curdoc().unhold()
> 
> def plot(self) -\> None:
> curdoc().hold("combine")
> data = random\_coords()
> self.\_my\_plot = MyPlot(data)
> print("plot:", self.\_my\_plot.plot)
> self.\_render\_container.children\[0\] = self.\_my\_plot.plot
> self.\_loading\_container.visible = False
> self.\_render\_container.visible = True
> curdoc().unhold()
>         
> def plot\_delayed(self, event) -\> None:
> self.display\_loading()
> curdoc().add\_next\_tick\_callback(self.plot) 
>         
> my\_frame = MyFrame()
>         
> button = Button(label='Create')
> button.on\_event('button\_click', my\_frame.plot\_delayed)
>        
> layout = column(my\_frame.layout, button)
> 
> curdoc().add\_root(layout)
> \`\`\`
> 
> \### Additional Info
> 
> To trigger the bug, the "Create" button has to be hit \*twice\*. The first click works fine, but each click afterwards produces the error.
> 
> In order to make my code example quicker to read, I tried to reduce it further, especially by removing the loading screen. The bug stops to exist at some point. The quickest way to make it disappear is by removing the lines which make the "container" objects visible or invisible.
> 
> I already posted the issue in the Bokeh forums (initially in a different form) and we had some discussion regarding it:
> https://discourse.bokeh.org/t/bug-with-deserializationerror-when-changing-content-layout-in-bokeh-3-1-1/10566/8
> \[And I also have another post on SO: \[https://stackoverflow.com/questions/76506289/bokeh-3-1-1-deserializationerror-when-changing-layout-content\](https://stackoverflow.com/questions/76506289/bokeh-3-1-1-deserializationerror-when-changing-layout-content) \]
> 
> Note that while in this reduced example, I could easily fix the code by replacing the source of the plot instead of the whole plot at all, I dislike this strategy in the big picture. The actual plots I am using have a lot of elements, and changing their sources seems error-prone to me, possible carrying over artifacts from old plots.
> 
> Also, my actual code (which was the base for the reduced code) worked without this error under Bokeh 2.4.3, and it occured only after updating to Bokeh 3.1.1.
> 
> \### Stack traceback in Anaconda Powershell
> 
> \`\`\`
> 2023-06-23 11:44:24,383 error handling message
> message: Message 'PATCH-DOC' content: {'events': \[{'kind': 'ModelChanged', 'model': {'id': 'p1074'}, 'attr': 'inner\_width', 'new': 0}, {'kind': 'ModelChanged', 'model': {'id': 'p1074'}, 'attr': 'inner\_height', 'new': 0}, {'kind': 'ModelChanged', 'model': {'id': 'p1074'}, 'attr': 'outer\_width', 'new': 0}, {'kind': 'ModelChanged', 'model': {'id': 'p1074'}, 'attr': 'outer\_height', 'new': 0}\]}
> error: DeserializationError("can't resolve reference 'p1074'")
> Traceback (most recent call last):
> File "C:\\Users\\\<my username\>\\anaconda3\\lib\\site-packages\\bokeh\\server\\protocol\_handler.py", line 97, in handle
> work = await handler(message, connection)
> File "C:\\Users\\\<my username\>\\anaconda3\\lib\\site-packages\\bokeh\\server\\session.py", line 94, in \_needs\_document\_lock\_wrapper
> result = func(self, \*args, \*\*kwargs)
> File "C:\\Users\\\<my username\>\\anaconda3\\lib\\site-packages\\bokeh\\server\\session.py", line 288, in \_handle\_patch
> message.apply\_to\_document(self.document, self)
> File "C:\\Users\\\<my username\>\\anaconda3\\lib\\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 "C:\\Users\\\<my username\>\\anaconda3\\lib\\site-packages\\bokeh\\document\\callbacks.py", line 443, in invoke\_with\_curdoc
> return f()
> File "C:\\Users\\\<my username\>\\anaconda3\\lib\\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 "C:\\Users\\\<my username\>\\anaconda3\\lib\\site-packages\\bokeh\\document\\document.py", line 369, in apply\_json\_patch
> patch: PatchJson = deserializer.deserialize(patch\_json)
> File "C:\\Users\\\<my username\>\\anaconda3\\lib\\site-packages\\bokeh\\core\\serialization.py", line 501, in deserialize
> return self.decode(obj.content, obj.buffers)
> File "C:\\Users\\\<my username\>\\anaconda3\\lib\\site-packages\\bokeh\\core\\serialization.py", line 516, in decode
> return self.\_decode(obj)
> File "C:\\Users\\\<my username\>\\anaconda3\\lib\\site-packages\\bokeh\\core\\serialization.py", line 557, in \_decode
> return {key: self.\_decode(val) for key, val in obj.items()}
> File "C:\\Users\\\<my username\>\\anaconda3\\lib\\site-packages\\bokeh\\core\\serialization.py", line 557, in \<dictcomp\>
> return {key: self.\_decode(val) for key, val in obj.items()}
> File "C:\\Users\\\<my username\>\\anaconda3\\lib\\site-packages\\bokeh\\core\\serialization.py", line 559, in \_decode
> return \[self.\_decode(entry) for entry in obj\]
> File "C:\\Users\\\<my username\>\\anaconda3\\lib\\site-packages\\bokeh\\core\\serialization.py", line 559, in \<listcomp\>
> return \[self.\_decode(entry) for entry in obj\]
> File "C:\\Users\\\<my username\>\\anaconda3\\lib\\site-packages\\bokeh\\core\\serialization.py", line 557, in \_decode
> return {key: self.\_decode(val) for key, val in obj.items()}
> File "C:\\Users\\\<my username\>\\anaconda3\\lib\\site-packages\\bokeh\\core\\serialization.py", line 557, in \<dictcomp\>
> return {key: self.\_decode(val) for key, val in obj.items()}
> File "C:\\Users\\\<my username\>\\anaconda3\\lib\\site-packages\\bokeh\\core\\serialization.py", line 555, in \_decode
> return self.\_decode\_ref(cast(Ref, obj))
> File "C:\\Users\\\<my username\>\\anaconda3\\lib\\site-packages\\bokeh\\core\\serialization.py", line 569, in \_decode\_ref
> self.error(f"can't resolve reference '{id}'")
> File "C:\\Users\\\<my username\>\\anaconda3\\lib\\site-packages\\bokeh\\core\\serialization.py", line 717, in error
> raise DeserializationError(message)
> bokeh.core.serialization.DeserializationError: can't resolve reference 'p1074'
> \`\`\`

---

<div class="post-metadata">

**Author:** ![Bryan](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/bryan/32/3625_2.png) [@Bryan](https://discourse.bokeh.org/u/Bryan)\
**Post date:** [June 23, 2023, 3:51pm UTC](https://discourse.bokeh.org/t/bug-with-deserializationerror-when-changing-content-layout-in-bokeh-3-1-1/10566/11 "2023-06-23T15:51:50Z")

</div>

@Aziuth My suggestion was directly in response to your statements about “hickups”:

> If I reverse the visibility assignments, one sees none for a split second, trading a “down” hickup for an “up” hickup. That’s a bit suboptimal - am I doing something wrong here?

_That_ (improvements to reduce “hickups” when doing multiple updates) is what I was suggesting an issue for.

The “deserialization error” is not really an error and, [as stated earlier](https://discourse.bokeh.org/t/bug-with-deserializationerror-when-changing-content-layout-in-bokeh-3-1-1/10566/4), has in fact been changed to reflect this in the 3.2 latest release by no longer presenting as an error message at all. There is no work to do regarding the “deserialization error”.

---

<div class="post-metadata">

**Author:** ![Aziuth](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/aziuth/32/6060_2.png) [@Aziuth](https://discourse.bokeh.org/u/Aziuth)\
**Post date:** [June 26, 2023, 9:25am UTC](https://discourse.bokeh.org/t/bug-with-deserializationerror-when-changing-content-layout-in-bokeh-3-1-1/10566/12 "2023-06-26T09:25:27Z")

</div>

Ah kay. Did so:

> <https://github.com/bokeh/bokeh/issues/13233>
>
> \### Software versions
> 
> Python version : 3.9.16 (main, Mar 8 2023, 10:39…:24) \[MSC v.1916 64 bit (AMD64)\]
> IPython version : 8.12.0
> Tornado version : 6.2
> Bokeh version : 3.2.0
> BokehJS static path : C:\\Users\\\<my username\>\\anaconda3\\lib\\site-packages\\bokeh\\server\\static
> node.js version : (not installed)
> npm version : (not installed)
> Operating system : Windows-10-10.0.22621-SP0
> 
> \### Browser name and version
> 
> Firefox 114.0.2 (64-bit)
> 
> \### Expected behavior
> 
> In the example code below, the goal is to have plot which can show a "loading screen" while data is processed (after hitting the Create button). In the example, random points are generated, but in a real life application, this would be especially for reading and processing data which can take notably long (over a second).
> For that, a plot which serves as a loading screen (empty plot except for a label that says "Loading") already exists as an object, is positioned at another place in a layout, and in order to switch from seeing the actual plot and the loading screen, visibility is changed.
> In order to have a smooth transition, each change of visibility is started by calling \`curdoc().hold("combine")\`, and ended with \`unhold\`.
> 
> \### Observed behavior
> 
> A smooth transition does not happen. For a split (but distracting) moment, we see both plots, and the button "hickups" downwards.
> If we change the order of the visibility assignments, we see no plot at all for a split moment, with the button hickup going upwards.
> Something like assigning both in the same assignment as tuple, hoping that it would behave somewhat atomic, doesn't work either.
> 
> In any case, I had expected that \`curdoc::hold\` would switch the plots at once anyway.
> 
> 
> \### Example code
> 
> \`\`\`Python
> from bokeh.plotting import figure, curdoc
> from bokeh.models import ColumnDataSource, Label, Button
> from bokeh.layouts import column
> from random import \*
> 
> def loading\_pic(width: int = 500, height: int = 500) -\> figure:
> plot = figure(x\_range=(0,width), y\_range=(0,height), width=width, height=height, tools='')
> pos\_x = width/2 
> pos\_y = height/2    
>     
> label\_size = min(height/4, width/4)
> label\_size\_str = str(label\_size)+'px'
>     
> loading\_label = Label(x=pos\_x, y=pos\_y, text='Loading', text\_font\_size = label\_size\_str,
> text\_align='center', text\_baseline='middle')
> plot.add\_layout(loading\_label)
>     
> plot.xaxis.visible = False
> plot.yaxis.visible = False
> plot.xgrid.grid\_line\_color = None
> plot.ygrid.grid\_line\_color = None
>     
> return plot
>     
> def random\_coords(maximum: float = 500, amount: int = 10000) -\> ColumnDataSource:
> data = ColumnDataSource()
> data.data\['x'\] = \[random()\*maximum for i in range(amount)\]
> data.data\['y'\] = \[random()\*maximum for i in range(amount)\]
> return data
>     
> class MyPlot:
>     
> def \_\_init\_\_(self, data: ColumnDataSource):
> self.plot = figure(x\_range=(0,500), y\_range=(0,500), width=500, height=500)
> self.plot.circle(source=data, x='x', y='y')
>     
> class MyFrame:
> 
> def \_\_init\_\_(self):
> 
> self.\_loading = loading\_pic()
> 
> self.\_loading\_container = column(self.\_loading)
> self.\_render\_container = column(column())
> self.\_render\_container.visible = False
>         
> self.layout = column(self.\_loading\_container, self.\_render\_container)
> 
> def display\_loading(self) -\> None:
> curdoc().hold("combine")
> self.\_loading\_container.visible = True
> self.\_render\_container.visible = False
> curdoc().unhold()
> 
> def plot(self) -\> None:
> curdoc().hold("combine")
> data = random\_coords()
> self.\_my\_plot = MyPlot(data)
> print("plot:", self.\_my\_plot.plot)
> self.\_render\_container.children\[0\] = self.\_my\_plot.plot
> self.\_loading\_container.visible = False
> self.\_render\_container.visible = True
> curdoc().unhold()
>         
> def plot\_delayed(self, event) -\> None:
> self.display\_loading()
> curdoc().add\_next\_tick\_callback(self.plot) 
>         
> my\_frame = MyFrame()
>         
> button = Button(label='Create')
> button.on\_event('button\_click', my\_frame.plot\_delayed)
>        
> layout = column(my\_frame.layout, button)
> 
> curdoc().add\_root(layout)
> 
> my\_frame.plot\_delayed(None)
> \`\`\`
> 
> 
> \### Additional Information
> 
> In order to trigger the behavior, simply click on the button.
> 
> I tested \`curdoc::hold\` by commenting the \`unhold\` and it stays frozen as expected, meaning the function does work, in some way. Also, in my actual bigger project, I use it successfully to accumulate small changes to a single plot.
> 
> This issue was created after discussions in the Bokeh forums, see https://discourse.bokeh.org/t/bug-with-deserializationerror-when-changing-content-layout-in-bokeh-3-1-1/10566/11
> 
> Note that the code is almost the exact same as in a different issue I posted recently.

---

<div class="post-metadata">

**Author:** ![system](https://discourse-uploads.bokeh.org/original/2X/1/14eb24f9e10e4e9b78e3f10f66c04ffa96446e5a.svg) [@system](https://discourse.bokeh.org/u/system)\
**Post date:** [September 24, 2023, 9:26am UTC](https://discourse.bokeh.org/t/bug-with-deserializationerror-when-changing-content-layout-in-bokeh-3-1-1/10566/13 "2023-09-24T09:26:02Z")

</div>

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