No Plotting appears but there are axes

I have been checking my code through and through. Even using chatgpt to find the errors. But I really don’t know what’s the problem, I cannot see my graph. I can only see the axes. Here is the output in image:

It is empty, my code is reading the data from a file. This is my first time using Bokeh, please help me to rectify the issue, I have been stuck here for so long. About a week.

Really appreciate your help to look at the code provided below. I did not get any error messages too, which is why it is hard for me to pinpoint where is the error specifically.

from datetime import datetime
from bokeh.plotting import figure, curdoc
from bokeh.models import ColumnDataSource, HoverTool
import traceback
    # Create a ColumnDataSource object to store the data
    source = ColumnDataSource(data=dict(x=[], y=[], url=[], color=[]))

    # Create a figure object
    p = figure(title="Real-time latency graph", x_axis_type='datetime', x_axis_label='Date & Time',
               y_axis_label='Latency (ms)')

    # Adjust the padding as needed
    p.x_range.range_padding = 0.1

    # Add a multi_line glyph to the figure
    p.multi_line(xs='x', ys='y', source=source, line_width=2, line_color='color', legend_field='url')

    # Add a hover tool to the figure
    hover = HoverTool(tooltips=[('Date & Time', '@x{%F %T}'), ('Latency (ms)', '@y{0.00}'), ('URL', '@url')])
    hover.formatters = {'@x': 'datetime'}

    # Set up the legend
    p.legend.location = 'top_left'
    p.legend.click_policy = 'hide'

    # Define a list of colors for the URLs
    url_colors = ['red', 'green', 'blue', 'orange', 'purple', 'yellow']

    def update_graph():
        xs, ys, urls, colors = [], [], [], []
        data = []
            with open(r"C:\Users\Anne\OneDrive - RIS Group\Desktop\TestLaData.txt", 'r') as f:
                for line in f:
                    parts = line.strip().split()
                    if len(parts) >= 4:
                        date_time = datetime.strptime(parts[0] + ' ' + parts[1], '%Y-%m-%d %H:%M:%S')
                        url = parts[2]
                        latency = float(parts[3])
                        # Assign a color to the URL based on its position in the list
                        color = url_colors[len(urls) % len(url_colors)]
                        data.append((date_time, latency, url, color))

            if not data:
                # Handle empty data
                p.y_range.start = 0
                p.y_range.end = 1
                p.x_range.start =
                p.x_range.end =
                # Set the y-axis range based on the data
                p.y_range.start = min(ys) - 10  # Adjust the range by a small margin
                p.y_range.end = max(ys) + 10
                # Set the x-axis range based on the data
                p.x_range.start = min(xs)
                p.x_range.end = max(xs)

            # Update the data in the ColumnDataSource object
   = dict(x=xs, y=ys, url=urls, color=colors)

        except Exception as e:
            print("Error occurred while updating the graph:")
            traceback.print_exc()  # Print the error traceback

    def update():
        except Exception as e:
            traceback.print_exc()  # Print the error traceback

    # Set up timer to redraw graph every 5 seconds

    # Display the figure using Bokeh server
    curdoc().title = "Canary Monitoring Websites"

except Exception as e:
    traceback.print_exc()  # Print the error traceback

This is the sample data stored in the file.

2023-05-10 15:28:00 201.19
2023-05-10 15:29:00 202.53
2023-05-10 15:30:00 202.13
2023-05-10 15:31:00 200.71
2023-05-10 15:32:00 197.95
2023-05-08 12:00:00 194.38
2023-05-08 12:01:00 198.71
2023-05-08 12:02:00 199.84

I see that you are using multi line glyph. I believe it uses data on the format list-of-lists. I do not know the format of the data you read from disk but I would check this.


@Jonas_Grave_Kristens is exactly correct, you are constructing a CDS with columns that are 1-d lists of numbers, but a multi_line glyphs expects columns that actually 2-d ragged arrays, i.e. a “list of lists” (or list of arrays) and it draw separate lines for each sub-array. There is an explicit example here:

Chances are you actually want to make multiple separate calls to line rather than multi_line. The line glyph does expect simple 1-d columns.

Lastly, please be aware that Bokeh can accept Pandas dataframes. Pandas can do all the file reading and datetime conversions, etc. and it would dramatically simplify the code above. See this chapter for more information:

1 Like

@Jonas_Grave_Kristens @Bryan Thank you for identifying the root cause. It is as what you mentioned about multi line glyph. I have changed my code to use Pandas and it works now.

1 Like