I have a multi line plot in Bokeh:
import pandas as pd
from bokeh.plotting import figure, show
from bokeh.palettes import Category20c_7
from bokeh.io import output_file
from bokeh.models import SingleIntervalTicker, LinearAxis, ColumnDataSource
output_file("conso_daily.html")
treatcriteria_daily_data = pd.read_csv("treatcriteria_evolution.csv", sep=';')
final_daily_data = treatcriteria_daily_data.groupby(['startdate_weekyear','startdate_dayweek'],as_index = False).sum().pivot('startdate_weekyear','startdate_dayweek').fillna(0)
# keep only integer values in x axis
def interval_integer(plot):
ticker = SingleIntervalTicker(interval=1, num_minor_ticks=1)
xaxis = LinearAxis(ticker=ticker)
plot.add_layout(xaxis, 'below')
numlines = len(final_daily_data.columns)
palette = Category20c_7[0:numlines]
# remove the last week if there is not all the data
data_without_last_week = final_daily_data[(final_daily_data != 0).all(1)]
cpu_values_daily = data_without_last_week.values.T.tolist()
weeks = []
for i in range(0,len(data_without_last_week.columns)):
weeks.append(data_without_last_week.index)
df = {'week': weeks,
'day': ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
'color': ['red', 'orange', 'yellow', 'green', 'grey', 'pink', 'purple'],
'HCPU': cpu_values_daily}
source = ColumnDataSource(df)
p = figure(width=800, height=500)
p.multi_line(xs='week', ys='HCPU', legend='day', color='color',
line_width=5, line_alpha=0.6, hover_line_alpha=1.0,
source=source)
p.xaxis.visible = False
p.left[0].formatter.use_scientific = False
interval_integer(p)
show(p)
I want to show legend outside the plot area because the top curve (Sunday) is hidden. I try to follow this thread, but it's for single lines and not for multiline: Create a two line legend in a bokeh plot
Using this code, I searched to show legend in right outside the plot area, but it doesn't work:
legend = Legend(items=[
('Monday', [p[0]]),
('Tuesday', [p[1]]),
('Wednesday', [p[2]]),
('Thursday', [p[3]]),
('Friday', [p[4]]),
('Saturday', [p[5]]),
('Sunday', [p[6]]),
], location=(0, -30))
p.add_layout(legend, 'right')
TypeError: 'Figure' object is not subscriptable
Thank you.
Edit: Here is my data 'final_daily_data' if it's useful:
mc_cpu_hours \
startdate_dayweek 1 2 3
startdate_weekyear
27 527644.000731 468053.338183 517548.838022
28 349896.850976 481313.693908 372385.568095
29 168595.113447 388117.184580 373894.548600
30 176007.786269 364379.872622 366155.953075
31 177517.591864 0.000000 0.000000
startdate_dayweek 4 5 6 7
startdate_weekyear
27 573669.325129 515710.534260 511711.421986 841073.028107
28 378069.713821 385937.231788 385856.666340 842468.209151
29 343235.942227 376405.876236 400007.946715 662019.708660
30 375948.240935 366151.336263 395790.387672 700936.336812
31 0.000000 0.000000 0.000000 686023.780120
Your problem is in legend = Legend(items=[('Monday', [p[0]]), ...])
or even more precise in p[0]
, ..., p[7]
. The figure objet is not subscriptable, because it is not a list or dictionary and this raises the error. I think in your case it is enough to define the Legend()
-class blank, without any further information.
Small Example
import pandas as pd
from bokeh.plotting import figure, show, output_notebook
from bokeh.models import Legend
output_notebook()
source = pd.DataFrame({
'xs':[[1,2,3,4],[1,2,3,4]],
'ys':[[1,2,3,4],[4,3,2,1]],
'label':['a','b'],
'color':['blue','green']
})
p = figure(width=400, height=300)
p.add_layout(Legend(),'right')
p.multi_line(xs='xs', ys='ys', legend_field ='label', color='color', source=source)
show(p)
Output