Efficiently update patch colors

I would like to know if there exists an easy color update for a single patch that I might be missing…

When using a circle glyph, one can update its color conveniently via a ColumnDataSource:

cds_circle = ColumnDataSource(data=dict(x=[5], y=[2], c=["#111aaa"]))
fig.circle(x='x', y='y', color='c', source=cds_circle, radius=2)

def change_circle_color():
    new_color = ...
    cds_circle.data['c'] = [new_color]

However for fig.patch(x='x', y='y', color='c', source=cds_patch) we get a value error. Ok, x and y have a different column length compared to c, but also if c is of the same length, the Value Error still appears. It makes sense since defining multiple colors for one patch has no clear meaning.

So I tried around a bit, and came to the conclusion, that there exist these different options:

  1. Using fig.patches (with one patch entry only)
  2. storing the GlyphRenderer object r = fig.patch(...) and change the color in the callback function via r.glyph.fill_color and r.glyph.line_color
  3. Using a tag in the patch (e.g. fig.patch(..., tags=["some_tag"]) ) and find the right renderer in the callback function by using this tag by searching through the list of fig.renderers.

The approach #2 was not available in my code, since that would have led to re-writing a lot of functions to return r over multiple levels.
#3 would do it, but always searching through all renderers of a figure seems like an over kill.
#1 seems to be the approach which would require the least changes. However I don’t feel very well using patches which is actually meant for multiple patches, while patch for a single patch would suffice. The only problem with the single patch is the color update issue.

Can I somehow update the color of a single patch via ColumnDataSource similar to the circle code example above?

You can’t. The Patch glyph only draws one patch, it is not “vectorized” in the same way most other Bokeh glyphs. As a result, it can’t accept a vector of colors like most of other Bokeh glyphs. The correct way to update the color of a patch is your option 2: set the (singular) r.glyph.fill_color and r.glyph.line_color.

Also, just trying to spare any future confusion:

Ok, x and y have a different column length compared to c,

That’s never OK :slight_smile: All columns in a CDS must always all have the same length at all times. Think of it as cheap version of a Pandas DataFrame (which also always has same-length columns). Mis-matched column lengths should usually generate an error, but in case it does not, just know any result is explicitly undefined behavior.

Yes, I know that I must avoid different column length, that’s why I tried it with just multiplying the color value list of length 1 in order to get a list of the length of x and y :sweat_smile:

So I will keep going with option #1 then, since option #2 would require some time consuming re-coding. But I will keep in mind the other way for the future :slightly_smiling_face:

Is there btw. any benefit in using Patch instead of Patches? :thinking:
Patches seem to be more flexible and if one uses a single Patch, a bit of additional computation time shouldn’t matter anyway.

If you only need to draw a single patch, it really comes down to preference and where you want to the differences due to the connected topology to surface:

  • in the data, having to provide a “list of list” vector for a single patch with Patches
  • in the visual properties, which cannot be vectorized and must be set on the glyph for Patch
1 Like