Reputation: 495
I have a piece of code that uses matplotlib to plot a set of lines and applies colors to those lines using a color map. The code excerpt and result are as follows:
cm = plt.cm.get_cmap('jet')
step = 15
xi = np.linspace(data[data.columns[0]].min(), data[data.columns[0]].max(), 2)
colors_l = np.linspace(0.1, 1, len(state_means[::step]))
for i, beta in enumerate(state_means[::step]):
plt.plot(xi, beta[0] * xi + beta[1], alpha=.2, lw=1, c=cm(colors_l[i]))
The relevant part of the code here is
c=cm(colors_l[i])
which is within the plt.plot() function. Here its is possible to index the color map using a parameter (i in this case).
However, if i try to accomplish something similar using bokeh, with its ColorMapper and line() glyph, i run into and error. The relevant code lines and output are
call_color_mapper = LinearColorMapper(palette="Viridis256", low=min(call_strike_vals), high=max(call_strike_vals))
call_lines=dict()
call_chain_plot = figure(y_axis_label='Call OI', x_axis_label='Dates', x_axis_type = 'datetime')
for strike in call_strikes:
call_lines[strike] = call_chain_plot.line('TIMESTAMP', strike, line_color=call_color_mapper(int(strike[2:])), source=callSource)
TypeError: 'LinearColorMapper' object is not callable
Is there a way to color a set of line glyphs using a color mapper in bokeh?
Upvotes: 3
Views: 7685
Reputation: 495
While @bigreddot 's solution does provide a great alternative to the line() glyph to plot a set of lines using a linear_cmap(), it does not provide a way to capture handles for the individual lines should the handles be needed for further processing (e.g. plotting a secondary y-axis for some of them). Which is the reason why i collect the handles to each line in a dictionary in my OP.
Well, another way to plot the lines one at a time while looping through a list is as follows
from bokeh.palettes import viridis #here viridis is a function that takes\
#parameter n and provides a palette with n equally(almost) spaced colors.
call_colors = viridis(len(call_strikes))
color_key_value_pairs = list(zip(call_strikes, call_colors))
color_dict = dict(color_key_value_pairs)
Now, the dictionary color_dict can be used to access colors based on the values in the dictionary. So, I run the code from the OP has follows:
call_lines=dict()
for index, strike in enumerate(call_strikes):
call_lines[strike] = call_chain_plot.line('xs', strike, color=color_dict[strike], source=callSource)
I guess this is what @bigreddot meant when he wrote, 'If you really need the colors in Python, you will have to map them by hand, there are lots of ways to do this'.
Upvotes: 2
Reputation: 34568
LinearColorMapper
does not compute colors in Python. Rather, LinearColorMapper
represents a color-mapping that happens in the browser, in JavaScript. If you really need the colors in Python, you will have to map them by hand, there are lots of ways to do this.
But you probably don't, so the best way to do this in Bokeh would be to use multi_line
instead of repeated calls to line
. This partially for performance reasons, Bokeh is optimized to perform best over "vectorized" operations. But also, it allows you to use the linear_cmap
convenience function to make a color mapper for any data column you like. Here is a complete example:
from bokeh.io import output_file, show
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure
from bokeh.transform import linear_cmap
output_file("cmap.html")
p = figure()
source = ColumnDataSource(data=dict(
xs=[[0,1] for i in range(256)], # x coords for each line (list of lists)
ys=[[i, i+10] for i in range(256)], # y coords for each line (list of lists)
foo=list(range(256)) # data to use for colormapping
))
p.multi_line('xs', 'ys', source=source,
color=linear_cmap('foo', "Viridis256", 0, 255))
show(p)
Upvotes: 8