Is there a possibility to achive plots like sample1 with Bokeh? Sample1 was created with Matplotlib. My goal is to plot multiple short lines which are separated from each other on the map. But the lines share the same source and are just different parts from the source within.
I already wrote a small script but with not so great results... (see Sample2). My skript draws 3 different lines on the map. Unfortunally the lines are linked together.
In Matplotlib it worked with for loops. But in Bokeh I try to use a slider to chose interactivly which data I like to see.
Sample1
Sample2
Here is my code:
from bokeh.io import output_file, show
from bokeh.models import ColumnDataSource, GMapOptions, CustomJS
from bokeh.plotting import gmap, ColumnDataSource, figure
from bokeh.layouts import column, row
from bokeh.models.widgets import RangeSlider
import numpy as np
# data set
lon = [[48.7886, 48.7887, 48.7888, 48.7889, 48.789],
[48.7876, 48.7877, 48.78878, 48.7879, 48.787],
[48.7866, 48.7867, 48.7868, 48.7869, 48.786]]
lat = [[8.92, 8.921, 8.922, 8.923, 8.924],
[8.91, 8.911, 8.912, 8.913, 8.914],
[8.90, 8.901, 8.902, 8.903, 8.904]]
# convert data set in 1D for callback function (JS slice)
lat1D = []
lon1D = []
for k in range(len(lon)):
lat1D += lat[k]
lon1D += lon[k]
# define source and map
source = ColumnDataSource(data = {'x': lon1D, 'y': lat1D})
map_options = GMapOptions(lat=48.7886, lng=8.92, map_type="satellite", zoom=13)
p = gmap("MY_API_KEY", map_options, title="Trajectory Map")
# plot lines on map
# for loops do not work like in matplotlib...
for j in range(0, len(lon1D), len(lon)):
for i in range(j, j + len(lon)):
p.line('y', 'x', source=source, line_width=0.4)
# slider to limit plotted data
range_slider = RangeSlider(title="Data Range Slider: ", start=0, end=len(lon1D), value=(0, len(lon1D)), step=1)
callback = CustomJS(args=dict(source=source, slider=range_slider, long=lon1D, lati=lat1D, lenght=len(lon)), code="""
var data = source.data;
const start = slider.value[0];
const end = slider.value[1];
data['x'] = long.slice(start, end)
data['y'] = lati.slice(start, end)
source.change.emit();
""")
range_slider.js_on_change('value', callback)
# Layout to plot and output
layout = row(
p, range_slider)
output_file("diag_plot_bike_data.html")
show(layout)
Anything that can be plotted with Matplotlib, can be plotted with Bokeh. Sometimes with a bit more code, sometimes with a bit less.
There are too many things going on in your code, so I'll answer in plain text:
multi_line
instead ofline
: https://docs.bokeh.org/en/latest/docs/user_guide/plotting.html#multiple-linesmulti_line
accepts lists of listsfor
loop doesn't work as intended because you're not using thej
andi
indices. But when you switch tomulti_line
, you won't even need the loopCustomJS
callbacks. You can limit the data, but expanding it will not be possible since the data will have already been lost. Instead, filter data with views and filters: https://docs.bokeh.org/en/latest/docs/user_guide/data.html#filtering-data