3.5 update change of behaviour for streaming data

Hello,

I’m sorry if this isn’t the right place to ask about this kind of problem, but going through the changelog and trying to update my codebase to adapt to the new update has not been successful.

I am currently building a system that represents live data in four plots. My system uses the Bokeh server to update the contents of a data source as new data is read from a growing local file.

The four plots consist of two color-mapped images and two line graphs. I started this project with Bokeh 3.4.1 and achieved a pretty stable result.

When I started updating to Bokeh 3.5, the behavior changed drastically. Now, every time my data is updated (a change in ColumnDataSource), the graph does not update but instead creates a smaller version of itself in the same visual space.

Here is a comparison between the behaviour of the same code in version 3.4.1 and 3.5

I can’t understand what caused this change in behavior.I went through the changelog and I played around with my code to see if new elements were added to the layout or inside the plots, but they were not. As of now, I can only conclude that this effect is created every time I change data in the data column, but that would not explain the original state where only one figure is displayed.

Providing a minimal reproducible example would be quite hard as the Bokeh plots are blended into the project, but here is how I create my plots and how I update them if it could help you.

class Spectrogram():
    def __init__(self,parameters:Spectrogram_Params,):
        print(parameters)
        #================================================================
        # Display Parameters
        #================================================================
        self.color_mapper = parameters.color_mapper
        self.color_bar = parameters.colorbar
        #================================================================
        # Stored Data
        #================================================================
        self.data_buffers = {
            "timestamps": [],
            "freqlist": np.empty(0),
        }
        #================================================================
        # Plot Tools
        #================================================================
        self.tools = []
        for tool in parameters.tools:
            match tool[0]:
                case "pan":
                    self.tools.append(PanTool())
                case "boxzoom":
                    self.tools.append(BoxZoomTool())
                case "wheelzoom":
                    self.tools.append(WheelZoomTool())
                case "save":
                    self.tools.append(SaveTool())
                case "hover":
                    self.tools.append(HoverTool(tooltips=parameters.tooltips,formatters={"$x":"datetime"}))
                case "tap":
                    self.tools.append(TapTool())
                case "reset":
                    self.tools.append(ResetTool())
                case _:
                    print("Unknown tool : ",tool[0])
            self.tools[-1].visible = tool[1]
        self.timestamp_formatter = DatetimeTickFormatter(hourmin='%H:%M:%S',minsec='%H:%M:%S',milliseconds='%H:%M:%S',seconds='%H:%M:%S',minutes='%H:%M:%S',days='%H:%M:%S',months='%H:%M:%S',years='%H:%M:%S')
        #================================================================
        # Plot Components
        #================================================================
        # Spectrogram
        self.source = ColumnDataSource(data={'image':[[]],'x':[[]],'y':[[]],'dw':[[]],'dh':[[]]})
        self.figure = figure(title=parameters.title,x_axis_label=parameters.xaxis.label,y_axis_label=parameters.yaxis.label,x_axis_type=parameters.xaxis.data_type,y_axis_type=parameters.yaxis.data_type,sizing_mode='stretch_width',toolbar_location='above',tools=self.tools,)
        if parameters.xaxis.temporal:
            self.figure.xaxis[0].formatter = self.timestamp_formatter
        self.figure.x_range.range_padding = 0
        self.figure.y_range.range_padding = 0
        self.figure.toolbar.logo = None # type: ignore
        # Reticle
        self.source_reticle = ColumnDataSource(data={'hx':[[0,0]],'hy':[[0,0]],'vx':[[0,0]],'vy':[[0,0]]})
        #================================================================
        # Plot state
        #================================================================
        self.reticle_displayed = 0


def update_data(self,timestamps:list|np.ndarray,matrix:np.ndarray,freqlist:np.ndarray,length:int=2048):
        #Replace buffers if necessary
        #print(len(timestamps),matrix.shape,freqlist,flush=True)
        print(timestamps,matrix,freqlist,length,flush=True)
        if (freqlist != np.linspace(0,100,length)).all() or len(self.data_buffers['freqlist']) == 0:
            self.data_buffers['freqlist'] = freqlist
        self.data_buffers['timestamps'] = timestamps

        # Update data sources
        self.source.data.update(x =[timestamps[0]],dw=[timestamps[-1]-timestamps[0]],y=[self.data_buffers['freqlist'][0]],dh=[self.data_buffers['freqlist'][-1] - self.data_buffers['freqlist'][0]],image=[matrix])
        self.update_reticle()

It also seems important to say that these figures are displayed in a row and column layout and added as the root in the curdoc element.

I will continue to look into this matter , but if anyone else has run into this issue or have any ideas on how to fix it. I would take any advice

Thanks in advance for your help.

This is clearly a bug, please open a GitHub Issue with full details.

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