Seismic bokeh plot



In [1]:
import glob
from obspy.core import read

In [2]:
singlechannel = read("./5_trace.mseed")

In [3]:
print(singlechannel)


5 Trace(s) in Stream:
BK.BDM.00.LHE | 2015-09-16T22:54:31.069536Z - 2015-09-17T00:54:30.069536Z | 1.0 Hz, 7200 samples
BK.BDM.00.LHN | 2015-09-16T22:54:31.069538Z - 2015-09-17T00:54:30.069538Z | 1.0 Hz, 7200 samples
BK.BDM.00.LHZ | 2015-09-16T22:54:31.069536Z - 2015-09-17T00:54:30.069536Z | 1.0 Hz, 7200 samples
BK.BKS.00.LHE | 2015-09-16T22:54:31.069538Z - 2015-09-17T00:54:30.069538Z | 1.0 Hz, 7200 samples
BK.BKS.00.LHN | 2015-09-16T22:54:31.069538Z - 2015-09-17T00:54:30.069538Z | 1.0 Hz, 7200 samples

In [4]:
# singlechannel.plot()

In [5]:
from bokeh.plotting import figure, output_file, show, vplot, hplot
from bokeh.models import CustomJS, ColumnDataSource

x1 = list(range(0,7200))
y1 = singlechannel[0].data

x2 = list(range(0,7200))
y2 = singlechannel[1].data

x3 = list(range(0,7200))
y3 = singlechannel[2].data

x4 = list(range(0,7200))
y4 = singlechannel[3].data

x5 = list(range(0,7200))
y5 = singlechannel[4].data

In [6]:
# output file
output_file("lines.html",title="line plot of seismic data",mode="cdn")

In [7]:
# plot 1
s1 = ColumnDataSource(data=dict(x=x1,y=y1))
p1 = figure(title="Seismic trace plot 1 select", plot_width=600, plot_height=300
            ,tools = "box_select")
# draw two plots - scatter plot and line plot
p1.circle('x','y',source=s1,alpha=0,fill_color="white")
p1.line('x','y',source=s1, line_width=0.2, line_color="red",alpha=0.6)


Out[7]:
<bokeh.models.renderers.GlyphRenderer at 0x10835d518>

In [32]:
# create a plot where the selection is shown
s1_watch = ColumnDataSource(data=dict(x=[],y=[]))
s2_watch = ColumnDataSource(data=dict(x=[],y=[]))
p1_watch = figure(title="Seismic trace plot 1 watch", plot_width=600, plot_height=1200, tools=['ywheel_zoom'])
p1_watch.line('x','y',source=s1_watch, line_width=0.2,line_color="black")
p1_watch.line('x','y',source=s2_watch, line_width=0.2,line_color="red")


Out[32]:
<bokeh.models.renderers.GlyphRenderer at 0x10a31e748>

In [33]:
#JS callback to draw
s1.callback = CustomJS(args=dict(s1_watch=s1_watch), code="""
    
    inds = cb_obj.get('selected')['1d'].indices;
    console.log(cb_obj)
    d1 = cb_obj.get('data');
    d2 = s1_watch.get('data');
    d2['x'] = []
    d2['y'] = []
    d3 = []
    // Change to int
    for (i=0; i<inds.length;i++) {
    d3.push(parseInt(d1['x'][inds[i]]))
    }
    d3.sort(function(a, b){return a-b});
    for (i=0;i<d3.length;i++) {
    
        pos = d1['x'].indexOf(d3[i])
        d2['y'].push(parseInt(d1['y'][pos]))
        d2['x'].push(parseInt(d1['x'][pos]))
    }
    s1_watch.trigger('change');
""")

In [34]:
# plot 2
s2 = ColumnDataSource(data=dict(x=x2,y=y2))
p2 = figure(title="Seismic trace plot 2 select", plot_width=600, plot_height=300
           ,tools = "box_select")
# two plots - scatter and line
p2.circle('x','y',source=s2,alpha=0,line_color="white",fill_color="white")
p2.line(x2, y2, legend="Trace 2", line_width=0.2, line_color = "green")


Out[34]:
<bokeh.models.renderers.GlyphRenderer at 0x10a31ecc0>

In [35]:
# try to call JS into the same plot window as before
s2.callback = CustomJS(args=dict(s2_watch=s2_watch), code= """
    var inds = cb_obj.get('selected')['1d'].indices;
    var d1 = cb_obj.get('data');
    var d2 = s2_watch.get('data');
    d2['x'] = []
    d2['y'] = []
    d3 = []
    // Change to int
    for (i=0; i<inds.length;i++) {
    d3.push(parseInt(d1['x'][inds[i]]))
    }
    d3.sort(function(a, b){return a-b});
    for (i=0; i<d3.length;i++) {
        pos = d1['x'].indexOf(d3[i])
        d2['y'].push(parseInt(d1['y'][pos]))
        d2['x'].push(parseInt(d1['x'][pos]))
    }
    s2_watch.trigger('change');
""")

In [36]:
from bokeh.models.widgets import Slider
from bokeh.io import output_file, show, vform

In [37]:
slider_callback = CustomJS(args=dict(source=s1_watch,p1_watch=p1_watch), code="""
   data = source.get('data');
   var amp = amplitude.get('value')
   if(data['orig_y'] === undefined) {
       data['orig_y'] = JSON.parse(JSON.stringify(data['y']))
   }
   console.log(amp)
   console.log(p1)
   y = data['y']
   orig_y = data['orig_y']
   for (i=0; i<y.length; i++) {
       y[i] = orig_y[i] * amp
   }
   //console.log(y)
   // data['y'] = y
   source.trigger('change');
""")

In [74]:
slider_callback = CustomJS(args=dict(source=s1_watch,y_range=p1_watch.y_range), code="""
   data = source.get('data');
   var amp = amplitude.get('value')
   if(data['orig_yrange'] === undefined) {
       data['orig_yrange'] = [y_range.get('start'), y_range.get('end')];
   }
   console.log(amp)
   console.log(y_range)

   orig_yrange = data['orig_yrange']
   y_range.set('start', orig_yrange[0] * amp)
   y_range.set('end', orig_yrange[1] * amp)

   //console.log(y)
   // data['y'] = y
   source.trigger('change');
""")

In [75]:
# add a slider to change amplitude
amplitude_slider = Slider(start=0, end=10, value=1, step=.1, title="Amplitude",name="Amplitude",callback=slider_callback)
slider_callback.args['amplitude'] = amplitude_slider

In [76]:
layout = vplot(p1,p2,vform(amplitude_slider))
p = hplot(layout,p1_watch)

In [77]:
# def update_data(self):
#     amp = self.amplitude.value
#     self.source.y_range.start = self.source.y_range.start*amp
#     self.source.y_range.end = self.source.y_range.end*amp
#     self.source.data['y'] = source.y_range
#     cursession().store_objects(x)

In [78]:
# amplitude.on_change('value',update_data)

In [79]:
# show results
show(p)

In [ ]:


In [ ]: