Search code examples
pythonpython-3.xbokeh

Is there a way to have multiple legend colour text in a bokeh chart?


I am working on an simple bar chart in bokeh, with the titanic dataset. I find the framework to be extremely flexible, however there is one last chart element i would like to control: the individual colours of the legend text.

Looking at the reference doc here ->

http://docs.bokeh.org/en/latest/docs/user_guide/styling.html#legends

I can see how to adjust the colour of the legend text (as a whole), however i would like to be able to colour of "First" to match the same colour as my column colour (i.e. #3a6587), and "Second" and "Third" as colour #aeb3b7

I include my sample code below:

from bokeh.io import show, output_file
from bokeh.models import ColumnDataSource
from bokeh.palettes import Spectral6
from bokeh.plotting import figure
from bokeh.transform import factor_cmap

output_file("bar_colormapped.html")

ticket = ['First', 'Second', 'Third']
counts = [84.15, 20.66, 13.68]


# .var width parameter controls the width of the columns
# We can add the colours to the barchart as part of a palette list.
# Note the width to height ration should be 1.618:1 ish ;-)

source = ColumnDataSource(data=dict(ticket=ticket, counts=counts))

p = figure(x_range=ticket, plot_height=480, plot_width= 647, toolbar_location=None, 
    title="Average Titanic Fare, by Class")
p.vbar(x='ticket', top='counts', width=0.7, source=source, legend="ticket",
       line_color='white', fill_color=factor_cmap('ticket', 
        palette=['#3a6587', '#aeb3b7', '#aeb3b7'], factors=ticket))


# Removes the chart gridlines (i.e.. removes the chart clutter)
p.xgrid.grid_line_color = None
p.ygrid.grid_line_color = None

# change just some things about the x-axes
p.xaxis.axis_label = "Class Type"
p.xaxis.axis_line_width = 2
p.yaxis.major_label_text_color = "#aeb3b7"
p.xaxis.axis_line_color = "#aeb3b7"


# change just some things about the y-axes
p.yaxis.axis_label = "Average Fare Price (in Pounds)"
p.yaxis.axis_line_width = 2
p.yaxis.major_label_text_color = "#aeb3b7"
p.yaxis.axis_line_color = "#aeb3b7"
p.yaxis.major_label_orientation = "vertical"


# Set the range of the chart
p.y_range.start = 0
p.y_range.end = 90


# Remove the border. Set the width to 0 does not work so we need 
# to set to 0.1 to make it less visible.
p.outline_line_width = 0.1

# Set attributes for the chart title
p.title.text_color = "black"
#p.title.text_font = "times"
#p.title.text_font_style = "italic"
p.title.align = "center"


# Set the position and orientation of the legend and remove 
# the legend border
p.legend.orientation = "vertical"
p.legend.location = "top_right"
p.legend.border_line_width = 0.1


show(p)

A mockup of a proposed image is included below:

Propsed Legend Text


Solution

  • As of Bokeh 1.0.4 legends only support a single text color across all entries. No one has ever asked about this before, but it would be reasonable to make a feature request on GitHub about it (especially if you would be interested in helping contribute).