Reputation: 1933
I am trying to reverse the order of the legend items in a stacked bar plot using hvplot or holoviews. Enabling the legend in a stacked bar plot displays the items in the opposite order of how they are stacked. One would expect them to be in the same order.
It seems that after render the holoviews plot to bokeh plot, the individual legend items can't be accessed with my_bokeh_plot.legend.items
. I just get a single legend item [LegendItem(id='1374', ...)]
. That means I can't revert the order of legend items with p.legend[0].items.reverse()
. I guess this is because hvplot and holoviews use sort of "groupby legends" of bokeh. How can I revert the order of the legend entries when using bokeh as backend?
Here an hvplot example:
import pandas as pd
import hvplot.pandas
from bokeh.plotting import show
import holoviews as hv
df = pd.DataFrame({
'Type': ['A', 'A', 'A', 'A', 'B', 'B', 'B', 'B'],
'Fiscal Period': ['2019-01', '2019-01', '2019-02', '2019-02', '2019-01', '2019-01', '2019-02', '2019-02'],
'Request Type': ['S', 'D', 'S', 'D', 'S', 'D', 'S', 'D'],
'values': range(1, 9),
})
layout = df.hvplot.bar(
x='Fiscal Period',
y='values',
by='Request Type',
groupby='Type',
stacked=True,
cmap='Category20',
legend='top_left',
frame_width=200,
).layout()
plotA = layout['A'].opts(title='Type: A')
my_bokeh_plot = hv.render(plotA, backend='bokeh')
my_bokeh_plot.legend[0].items.reverse()
show(my_bokeh_plot)
Related discussions I found so far:
https://github.com/bokeh/bokeh/issues/9135
Upvotes: 4
Views: 894
Reputation: 115
One solution consists in using the matplotlib backend of hvplot (released with hvplot 0.8.0
) and then reverse the legend order with matplotlib.
For your example code, it would be:
import pandas as pd
import hvplot.pandas
import holoviews as hv
hv.extension('matplotlib') # use matplotlib backend
df = pd.DataFrame({
'Type': ['A', 'A', 'A', 'A', 'B', 'B', 'B', 'B'],
'Fiscal Period': ['2019-01', '2019-01', '2019-02', '2019-02', '2019-01', '2019-01', '2019-02', '2019-02'],
'Request Type': ['S', 'D', 'S', 'D', 'S', 'D', 'S', 'D'],
'values': range(1, 9),
})
layout = df.hvplot.bar(
x='Fiscal Period',
y='values',
by='Request Type',
groupby='Type',
stacked=True,
cmap='Category20',
legend='top_left',
frame_width=200,
).layout()
plotA = layout['A'].opts(title='Type: A')
fig = hv.render(plotA)
# Reverse legend order
ax = fig.axes[0]
title = ax.get_legend()._legend_title_box._text.get_text() # Access legend title
handles, labels = ax.get_legend_handles_labels()
ax.legend(handles[::-1], labels[::-1], title = title)
fig
Upvotes: 1