0

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

Sample1

Sample2

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)
Pm740
  • 339
  • 2
  • 12

1 Answers1

2

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:

Eugene Pakhomov
  • 9,309
  • 3
  • 27
  • 53
  • Thank you for your answer. It war really helpful! I decided to go with on_change instead of js_on_change for the range_slider. Now I have some trouble with my callback function... I want to alter my IndexFilter for my plots with the range_slider. How can I acomplish this task when I acess my plot.view directly in the callback it won't work... :/ – Pm740 Oct 20 '20 at 19:59
  • It seems to be a completely separate question from this one. Could please ask a new question, with the full code? Just make sure to put the `bokeh` tag in there and I will check it out. – Eugene Pakhomov Oct 20 '20 at 23:11