Bokeh plotting rectangle

Hello,

I’m trying to plot a set of rectangles with bokeh.plotting, and I’d like to use a gradient of colors in the rectangle instead of an unique color. Is it an easy way to do so, knowing that in order to plot a rectangle you just have to provide the coordinates of the center and width/height ?

Thank you for your answers !

The ability to add fill patterns to things was only recently added, so first off this is only possible at all with Bokeh 1.2 or later. However, as of 1.2, the rect glyph specifically does not have this feature yet. It is available for vbar, hbar, and quad at present. Assuming you can get by with one of those instead of rect, then presently you can add a gradient image as a fill pattern using ImageURLTexture like this:

p.vbar(...
       hatch_pattern=dict(value='image'), 
       hatch_extra={"image": ImageURLTexture(url=url)})

The url can be a public http or https URL, or if you want everything self-contained, then base64 data: URLs also work (there is an online converter here). Since patterns normally repeat I think for a gradient you will simply have to choose images that are big enough to cover the entire area inside the glyphs. You may need to set the repetition property of the texture to turn off repeating explicitly.

Another option that is more flexible but so far not as well documented is to use a CanvasTexture, which allows you to draw arbitrary patterns on the HTML canvas using JavaScript:

custom = CanvasTexture(code="""
    // color, scale, and width parameters are available to refer to
    ctx.beginPath()
    ...
    ctx.fill()
""")

Theres’ probably some work still to be done to make this more useful, e.g. CanvasTexture should accept an args param like CustomJS callbacks so that it can access other models and properties when drawing.

Hi Bryan,

Could you please expand on the second option regarding with interacting with the canvas? I am trying to fit a linear gradient to fill the area below a varea().

With JS it is possible to apply this code to generate a gradient.

    const grad = context.createLinearGradient(0,0,0, gradientHeight);
    grad.addColorStop(0, `${plot.area.background.split(',', 3)},0.75)`);
    grad.addColorStop(1, `${plot.area.background.split(',', 3)},0)`);
    context.fillStyle = grad;

Can this implemented in Bokeh?

Thanks.

1 Like

@hernang4 I think in general gradients are going to be difficult, because it’s going to be difficult to know where to start and stop the gradient screen space, in order to over the glyph in a given data space (e.g. Bokeh does not currently expose bounding box information in a publicly accessible way). The fill pattern properties are much better for (and in fact designed for) small repeating patterns or images.

It’s possible under some assumptions a gradient can be workable, but I’ve never tried it myself. I’m happy to spend a short time tinkering on a script to see if anything works out, so long as the script you provide is complete and minimal, i.e. something that I can literally copy-paste into an editor and run immediately with no modifications at all.

@Bryan, thanks for your reply.

Please refer to this codepen for a very basic implementation of a gradient within the context of an area plot drawn upon a canvas object: D3 Gradient Area (codepen.io)

In that example the gradient extends the height of the plot and it is used to fill the current path. In this example, the color stays constant and only the alpha changes.

Let me know if there’s anything else that could be of use.

Thanks.

@hernang4 Sorry, I was not clear. I am asking for a Python script that uses Bokeh to draw rectangles that has an initial (non-working) stab at implementing a CanvasTexture.

Also FYI Bokeh does no use d3 anywhere in its implementation, so d3 code is not really relevant. Bokeh renders directly on an HTML canvas element.

@Bryan It’s ok. However I may only be able to provide you with a basic bar/area plot using dummy data as that’s as far as I could go using the documentation.

Let’s for a moment think beyond D3, what matters in the codepen I posted before is this:

const grad = ctx.createLinearGradient(0, 0, 0, height);
grad.addColorStop(0, "rgba(39,155,143,0.75)");
grad.addColorStop(1, "rgba(39,155,143,0)");
ctx.fillStyle = grad;

D3 just creates a path and this path is filled using the gradient as shown above. I could generate the path using native canvas methods, which would yield equal results, because the important part is the assignment of the gradient to the fillStyle of the rendering context.

Somehow, the code I wrote before could be inserted within this code you wrote earlier.

However, I fail to grasp where you are assigning the CanvasTexture object. What argument within the glyph API is receiving it?

Thanks for your time.

It is configure as hatch_extra the same as in my response above:

except with a CanvasTexture instead of an ImageURLTexture. There is also an example here in the PR that added the feature: Add hatching fill patterns by bryevdv · Pull Request #8859 · bokeh/bokeh · GitHub