I am by no means a pro here so there are bound to be lots of things overlooked. This is just a collection of some recent experimentations that I though could/would be useful.
Most interactive graphing tools are somehow based on JavaScript but still rely on a python backend for more flexible complex compute (and generally default to this when availible?)
These libraries generally provide a method for creating the div and scripts associated which we can harness and modify
Dieter Werthmüller - Impulse response over resistive halfspace
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, CustomJS, Slider, Title
from bokeh.plotting import Figure
import numpy as np
import empymod
time = np.logspace(-3, 1, 301)
epminp = {'src': (0, 0, 0), 'rec': (3000, 0, 0), 'freqtime': time,
'solution': 'dhs', 'signal': 0, 'verb': 1}
efield = empymod.analytical(res=50, **epminp)
source = ColumnDataSource(data=dict(time=time, efield=efield))
# Create callback
callback = CustomJS(
args=dict(source=source),
code="""
var data = source.data;
var res = cb_obj.value
var time = data['time']
var efield = data['efield']
var tau = data['tau']
var off = 3000
var mu0 = 4*Math.PI*1e-7
var tau = 0
var fact1 = 0
var fact2 = 0
var fact3 = 0
for (var i = 0; i < time.length; i++) {
tau = Math.sqrt(mu0 * Math.pow(off, 2) / (res * time[i]));
fact1 = res / (2 * Math.PI * Math.pow(off, 3));
fact2 = Math.pow(tau, 3) / (4 * time[i] * Math.sqrt(Math.PI));
fact3 = Math.exp(- Math.pow(tau, 2)/4);
efield[i] = fact1 * fact2 * fact3;
}
source.change.emit();
"""
)
# Create slider
slider = Slider(start=1, end=100, value=49, step=1, title="Resistivity (Ohm.m)")
# Attach callback to slider
slider.js_on_change('value', callback)
# Create figure
p = Figure(plot_width=600, plot_height=400, x_axis_type="log",
tools='pan,wheel_zoom,box_zoom,reset, hover')
# Plot empymod-responses for QC
for r in [1, 25, 50, 75, 100]:
epm = empymod.analytical(res=r, **epminp)
p.line(time, epm, line_color='black', line_width=1)
# Plot interactive JS result
p.line('time', 'efield', source=source, line_width=3, line_alpha=0.6)
p.add_layout(Title(text='Impulse response over a halfspace', align="center"), "above")
p.xaxis.axis_label = "Time (s)"
p.yaxis.axis_label = "Amplitude (V/m)"
# Creaty layout and show
layout = column(p, slider)
#Open dataset
ds = xr.open_dataset("/Users/wesleybanfield/Downloads/10MaParathetys_v4_topo_fixed_routing_netcdf_flask_app-2.nc")
# Create dictionnary this is what is going to hold the data
d = {}
for data_var in ds.data_vars:
d[data_var] = [ds[data_var].values]
# Bokeh will only plot one varaible so the "trick" is to modify the values inside that variable inside the javascript callback
d["to_plot"] = [ds[list(ds.data_vars)[0]].values]
# Create the data source that is accesible from inside the javascript
source = ColumnDataSource(d)
# Create the javascript callback
# All we do here is update the values of the varaible "to_plot" with the ones chosen inside the selctor tool
callback = CustomJS(
args=dict(source=source),
code="""
var data = source.data;
data['to_plot'] = data[cb_obj.value];
source.change.emit();
""",
)
output_type='div'
import plotly.graph_objs as go
from plotly.offline import plot
trace = go.Scatter(
...
)
data = [trace]
# get the a div
div = plot(data, include_plotlyjs=False, output_type='div')
# retrieve the div id (you probably want to do something smarter here with beautifulsoup)
div_id = div.split('=')[1].split()[0].replace("'", "").replace('"', '')
# your custom JS code
js = '''
'''.format(div_id=div_id)
# merge everything
div = div + js