Adding a legend outside the plot area is possible even with auto-grouped, indirectly created legends

I thought that it was not possible to add a legend outside of the plot area unless the legend is created directly (as stated in the docs). However, I just discovered that it is:

from bokeh.models import CategoricalColorMapper, Legend
from bokeh.palettes import Category10
from bokeh.plotting import figure, show
from bokeh.sampledata.iris import flowers


color_mapper = CategoricalColorMapper(
    factors=[x for x in flowers['species'].unique()], palette=Category10[10])
p = figure(height=350, width=500)
p.add_layout(Legend(), 'right')
p.circle("petal_length", "petal_width", source=flowers, legend_group='species',
         color=dict(field='species', transform=color_mapper))
show(p)

Apparently bokeh prefers plotting into existing legend objects, so by creating an empty one outside the figure, subsequent glyphs with the legend_group parameter will fill in this legend object instead of creating a new one. At least that’s how I understand it.

Is this hack/feature considered stable? If so could I add a PR to the documentation with the sample above?

I would say it’s stable, because all glyph functions just use the existing legend, regardless of the way it was created.
Regarding the PR - it certainly won’t hurt, especially if there’s an accompanying issue.

I agree with @p-himik that this should be stable, but I do also think it is fragile and a burden on users, in the sense that a small re-ordering of operations will cause it not to work. You are exactly right that the helper methods will prefer an existing legend if one exists, and if not, will create one to use. But the one that is created is by default inside the plot. So that’s’ the issue in a nutshell. I’d love to improve things but I’d also toss out some other ideas:

  • Add a helper argument to figure to specify the default legend location (since the figure must be created first this would help ensure the proper ordering of operations)
  • Add a helper function to move legends. As is is, legend location is a function of what layout side legend is in, e.g. p.left, p.center. It’s a bit opaque that moving a legend mean moving it from one of those lists to the other. We could make API to simplify that
1 Like

Thanks for your responses @Bryan and @p-himik,
It would be interesting to try to add those functions to Bokeh, but for the time being I think it will be the most realistic for me timewise to focus on adding the example to the doc pages and then if the helper functions are implemented, they can replace the example. At least this shows that it is possible to do now in case someone needs it.

@joelostblom to be honest I think my preference would be an issue linking here and outlining the other options. My concerns with showing this approach are twofold:

  • it’s fragility means it might actually result in increased support burden
  • having to go back and remove anything later is also more work and extremely easy to get forgotten/overlooked

So I’d rather focus on getting an issue for the more thorough solutions, which we can also mark as Good First Issue

Thanks for voicing your preferences before I made a PR for the docs @Bryan! I opened an issue here.

1 Like

Awesome thanks @joelostblom!