Change color of a line based on some condition

Help us help you! Writing your post to the following guidelines will help Bokeh Discourse reviewers understand your question, and increases the likelihood of a response.

I want to change the color of a line based on some dataframe value, essentially I’m trying to do what I would think this would do. (As an aside, ChatGPT recommends I do this when asked to solve the problem):

p.line("x", "y", color="color", source=source)

Where source contains a “color” column so that the line segments that start with a color annotation have that color.

You can kinda do this with a set of lines and a data frame. For example with a boolean condition:

p.line(df[cond]['x'], df[cond]['y'], color='color1')
p.line(df[~cond]['x'], df[~cond]['y'], color='color2')

But it (rightly so!) interpolates between the different lines so you get long lines when the wrong condition is selected.

Unfortunately, manually grouping df into different chunks so I can color each one appropriately is really annoying and tedious, so I would expect Bokeh to work by being able to select a color using a column of the data frame or column data source.

Lines only support a single color, because they are a single, topologically connected entity. Additionally, the underlying HTML canvas API does not support distinct colors for sub-segments of lines, so therefore neither does Bokeh.

A workaround could be to use multi_line instead. That you allow draw all the sub-segments individually, including giving each one a different color. But this approach would lose some features, e.g. the the line glyph renders actual nice line-joins between all the sub-segments, but that would not be the case with multi_line.

As an aside, ChatGPT recommends I do this when asked to solve the problem

ChatGPT’s advice here is reasonable for almost all of Bokeh’s glyphs, but entirely wrong for line, specifically. That said, I’d also usually choose to use a client-side color-mapper rather than make an explicit column of colors in most cases.