Source code for arviz_plots.backend.bokeh.legend
"""Bokeh manual legend generation."""
import warnings
import numpy as np
from bokeh.models import Legend
def dealiase_line_kwargs(kwargs):
"""Convert arviz common interface properties to bokeh ones."""
prop_map = {"width": "line_width", "linestyle": "line_dash"}
return {prop_map.get(key, key): value for key, value in kwargs.items()}
[docs]
def legend(
target,
kwarg_list,
label_list,
title=None,
artist_type="line",
artist_kwargs=None,
legend_target=None,
side="auto",
legend_placement_threshold=600, # Magic number
**kwargs,
):
"""Generate a legend on a figure given lists of labels and property kwargs.
Parameters
----------
legend_target : (int, int), default (0, -1)
Row and colum indicators of the :term:`plot` where the legend will be placed.
Bokeh does not support :term:`figure` level legend.
side : str, optional
Side of the plot on which to place the legend. Use "center" to put the legend
inside the plotting area.
"""
if artist_kwargs is None:
artist_kwargs = {}
if legend_target is None:
legend_target = (0, -1)
# TODO: improve selection of Figure object from what is stored as "figure"
children = target.children
if not isinstance(children[0], tuple):
children = children[1].children
plots = [child[0] for child in children]
row_id = np.array([child[1] for child in children], dtype=int)
col_id = np.array([child[2] for child in children], dtype=int)
legend_id = np.argmax(
(row_id == np.unique(row_id)[legend_target[0]])
& (col_id == np.unique(col_id)[legend_target[1]])
)
target_plot = plots[legend_id]
if target_plot.legend:
warnings.warn("This target plot already contains a legend")
glyph_list = []
if artist_type == "line":
artist_fun = target_plot.line
kwarg_list = [dealiase_line_kwargs(kws) for kws in kwarg_list]
else:
raise NotImplementedError("Only line type legends supported for now")
for kws in kwarg_list:
glyph = artist_fun(**{**artist_kwargs, **kws})
glyph_list.append(glyph)
if side == "auto":
plot_width = target_plot.width
if plot_width >= legend_placement_threshold:
side = "right"
else:
side = "center"
leg = Legend(
items=[(str(label), [glyph]) for label, glyph in zip(label_list, glyph_list)],
title=title,
**kwargs,
)
target_plot.add_layout(leg, side)
return leg