Exemplo n.º 1
0
def slider(renderer, title, start, end, **kwargs):
    """
    TBD
    """
    js_callback_template = 'source.data["{key}"] = {lb}source2.data["{key}"][cb_obj.value]{rb};'
    lb, rb = ['[', ']'] if isinstance(renderer.glyph, bokeh.models.glyphs.Image) else ['','']
    js_slider_callback_source = '\n'.join(js_callback_template.format(key=key, lb=lb, rb=rb) for key in kwargs)
    js_slider_callback_source += '\nsource.change.emit();'
    source2 = ColumnDataSource(data=kwargs)
    slider = Slider(start=start, end=end, value=0, step=1, title=title)
    slider_callback = CustomJS(args=dict(source=renderer.data_source, source2=source2), code=js_slider_callback_source)
    slider.js_on_change('value', slider_callback)

    js_button_callback_source ='''
for (var i=slider.start; i <= slider.end; i++){
    setTimeout((source, slider, i) => {
        slider.value = i;
        source.change.emit();
    }, 20 * i, source, slider, i);
}
'''
    button_callback = CustomJS(args=dict(slider=slider, source=renderer.data_source, source2=source2), code=js_button_callback_source)
    button = Button(label="Play", button_type="success")
    button.js_on_event(events.ButtonClick, button_callback)
    return row(slider, button)
Exemplo n.º 2
0
 def build_button(self, button_size_pixels: int) -> Button:
     js_code_for_adio_playing = self._generate_js_code_for_audio_playing()
     callback = CustomJS(code=js_code_for_adio_playing)
     audio_button = Button(label='',
                           css_classes=[self.button_id],
                           width=button_size_pixels,
                           height=button_size_pixels)
     audio_button.js_on_event(ButtonClick, callback)
     return audio_button
Exemplo n.º 3
0
def run():
    print("run")
    dx = np.gradient(x)
    dy = np.gradient(y)
    ##        source.data = dict(x=x, y=dy)
    t1_stop = Event()
    thread = Thread(target=threaded_function, args=(1, t1_stop))
    thread.start()
    thread.join()
    print("Process finished...exiting")


# Set up layouts and add to document
inputs = widgetbox(dropdown, text, offset, amplitude, Speed, Delay, button,
                   button1)
button.js_on_event(events.ButtonClick, display_event(div))
dropdown.on_change('value', function_to_call)

button.on_click(run)
button1.on_click(stop)

curdoc().add_root(row(inputs, plot, width=1200))
curdoc().title = "Sliders"


def threaded_function(arg, stop_event):
    while (not stop_event.is_set()):
        for i in range(len(x)):
            print(x[i])
            circle = Circle(x=x[i], y=y[i], fill_color='red', size=3)
            ##        initial_circle = Circle(x='x', y='y', fill_color='blue', size=50)
Exemplo n.º 4
0
Arquivo: navia.py Projeto: d-que/navia

# Further options to implement ("Export SVG","expo_svg"), ("Export high-res PNG","expo_svg")]

ser_act.js_on_change('value', ser_callback)
posneg_menu=[('Positive Mode','Positive'), ('Negative Mode', 'Negative')]
posneg = Dropdown(menu=posneg_menu, value='Positive', label='Instrument Mode: +' , width=160, height=30)
graph_opt = Toggle(label='Figure', width=110, height=30)

help_alert = CustomJS(args=dict(), code=open(os.path.join(os.getcwd(), 'JS_Functions', "help_cb.js")).read())

mass_finder = Toggle(label='Mass Finder', width=110, height=30)
mass_match = Toggle(label='Complex Stoichiometry', width=150, height=30)
dt_button = Toggle(label='Data Processing', width=110, height=30)
help_button = Button(label='Help', width=90, height=30)
help_button.js_on_event(ButtonClick, help_alert)


sele_cb = CustomJS(args=dict(peak_mz=peak_mz, bg_mz=bg_mz, proc_mz=proc_mz, ser_act=ser_act, series_sele=series_sele, series_data=series_data, series_mz=series_mz,
                         series_names=series_names, series_masses=series_masses, pp_mean_data=pp_mean_data, pp_std_data=pp_std_data, aser_data=aser_data, posneg=posneg, series_colours_DS=series_colours_DS), code=open(os.path.join(os.getcwd(), 'JS_Functions', "navia_functions.js")).read()
                    + open(os.path.join(os.getcwd(), 'JS_Functions', "sele_cb.js")).read())

correct_cb = CustomJS(args=dict(series_colours_DS=series_colours_DS, peak_mz=peak_mz, bg_mz=bg_mz, proc_mz=proc_mz, ser_act=ser_act, series_sele=series_sele, series_data=series_data, series_mz=series_mz,
                         series_names=series_names, series_masses=series_masses, pp_mean_data=pp_mean_data, pp_std_data=pp_std_data, aser_data=aser_data, posneg=posneg), code=open(os.path.join(os.getcwd(), 'JS_Functions', "navia_functions.js")).read()
                    + open(os.path.join(os.getcwd(), 'JS_Functions', "correct_cb.js")).read())
posneg_cb = CustomJS(args=dict(series_colours_DS=series_colours_DS, peak_mz=peak_mz, bg_mz=bg_mz, proc_mz=proc_mz, ser_act=ser_act, series_sele=series_sele, series_data=series_data, series_mz=series_mz,
                         series_names=series_names, series_masses=series_masses, pp_mean_data=pp_mean_data, pp_std_data=pp_std_data, aser_data=aser_data, posneg=posneg), code=open(os.path.join(os.getcwd(), 'JS_Functions', "navia_functions.js")).read()
                    + open(os.path.join(os.getcwd(), 'JS_Functions', "posneg_cb.js")).read())
posneg.js_on_change('value', posneg_cb)

class DQTapTool(TapTool):
Exemplo n.º 5
0
                                     value=str(DEFAULT_DETECTOR_THICKNESS))
detector_density_input = TextInput(title='density',
                                   value=str(DEFAULT_DETECTOR_DENSITY))

p = Paragraph(text="", width=500)
p.text = f"Running roentgen version {roentgen.__version__}"

columns = [
    TableColumn(field="x", title="energy [keV]"),
    TableColumn(field="y", title="Percent"),
]
data_table = DataTable(source=source, columns=columns, width=400, height=700)

download_button = Button(label="Download", button_type="success")
download_button.js_on_event(
    ButtonClick,
    CustomJS(args=dict(source=source),
             code=open(join(dirname(__file__), "download.js")).read()))


def convert_air_pressure(value, current_unit, new_unit):
    if current_unit == "atm":
        air_pressure = u.Quantity(value * const.atm, "Pa")
    elif current_unit == "torr":
        air_pressure = u.Quantity(value * const.atm / 760., "Pa")
    else:
        air_pressure = u.Quantity(value, current_unit)

    if new_unit == "atm":
        return (air_pressure.to("Pa") / const.atm).value
    elif new_unit == "torr":
        return (air_pressure.to("Pa") / const.atm).value * 760.0
def intplotter(data, isodata, nodata, y, hetclassintdf):
    linewidth = 1.5
    source = ColumnDataSource(data)
    s2 = ColumnDataSource(data=dict(mz=data["mz"],
                                    Error=data["Error"],
                                    RA=data["RA"],
                                    Formula=data["Formula"],
                                    HeteroClass=data["HeteroClass"]))
    isosource = ColumnDataSource(isodata)
    nosource = ColumnDataSource(nodata)
    url = "http://www.chemspider.com/Search.aspx?q=@Formula"
    TOOLS = "crosshair,pan,wheel_zoom,box_zoom,reset,tap,save,box_select,poly_select,lasso_select,hover"

    figdims = (900, 500)  #pixel dimensions for the normal figures
    msxlim = [200, 700]  #x limits in m/z for the mass spectra

    vkxlim = [0, 1]
    vkylim = [0, 2]
    p1 = figure(tools=TOOLS,
                title=y[:-9] + " - Van Krevelen",
                width=figdims[0],
                height=figdims[1],
                x_axis_label='O/C',
                y_axis_label='H/C',
                x_range=vkxlim,
                y_range=vkylim)
    color_mapper = LinearColorMapper(palette=glocmap,
                                     low=msxlim[0],
                                     high=msxlim[1])
    p1.scatter(x='OC',
               y='HC',
               source=source,
               size='VKsize',
               fill_color={
                   'field': 'mz',
                   'transform': color_mapper
               },
               fill_alpha=0.75,
               line_color=None)  #use size not radius.
    hover = p1.select(dict(type=HoverTool))
    hover.tooltips = OrderedDict([('Formula', "@Formula"),
                                  ('Mass', "@mz{1.11111}"),
                                  ('Error (ppm)', "@Error{1.11}")])
    taptool = p1.select(type=TapTool)
    taptool.callback = OpenURL(url=url)

    color_bar = ColorBar(color_mapper=color_mapper,
                         title="m/z",
                         border_line_color=None,
                         location=(0, 0),
                         scale_alpha=0.7)
    #orientation='horizontal',location='top_left', scale_alpha=0.7)#,ticker=FixedTicker(ticks=[2,6,10,14,18]))
    p1.add_layout(color_bar, "right")

    dbexlim = [0, 45]
    dbeylim = [0, 40]
    cmax = max(data["O"])
    cmax = int(5 * round(float(cmax) / 5))
    p2 = figure(tools=TOOLS,
                title=y[:-9] + " - DBE vs C# Plot",
                width=figdims[0],
                height=figdims[1],
                x_axis_label='C#',
                y_axis_label='DBE',
                x_range=dbexlim,
                y_range=dbeylim)
    color_mapper2 = LinearColorMapper(palette=glocmap2, low=0, high=cmax)
    p2.scatter(x='C',
               y='DBE',
               source=source,
               size='VKsize',
               fill_color={
                   'field': 'O',
                   'transform': color_mapper2
               },
               fill_alpha=0.75,
               line_color=None)
    hover = p2.select(dict(type=HoverTool))
    hover.tooltips = OrderedDict([('Formula', "@Formula"),
                                  ('Mass', "@mz{1.11111}"),
                                  ('Error (ppm)', "@Error{1.11}")])
    taptool = p2.select(type=TapTool)
    taptool.callback = OpenURL(url=url)

    color_bar2 = ColorBar(
        color_mapper=color_mapper2,
        title="O#",
        border_line_color=None,
        location=(0, 0),
        scale_alpha=0.7,
        ticker=FixedTicker(
            ticks=[0, int(cmax / 4),
                   int(cmax / 2),
                   int(3 * cmax / 4), cmax]))
    p2.add_layout(color_bar2, "right")

    aixlim = [0, 45]
    aiylim = [0, 1]

    p3 = figure(tools=TOOLS,
                title=y[:-9] + " - AI(mod) vs C# Plot",
                width=figdims[0],
                height=figdims[1],
                x_axis_label='C#',
                y_axis_label='AI(mod)',
                x_range=aixlim,
                y_range=aiylim)
    color_mapper3 = LinearColorMapper(palette=glocmap2, low=0, high=cmax)
    p3.scatter(x='C',
               y='AImod',
               source=source,
               size='VKsize',
               fill_color={
                   'field': 'O',
                   'transform': color_mapper3
               },
               fill_alpha=0.75,
               line_color=None)
    hover = p3.select(dict(type=HoverTool))
    hover.tooltips = OrderedDict([('Formula', "@Formula"),
                                  ('Mass', "@mz{1.11111}"),
                                  ('Error (ppm)', "@Error{1.11}")])
    taptool = p3.select(type=TapTool)
    taptool.callback = OpenURL(url=url)
    color_bar3 = ColorBar(
        color_mapper=color_mapper3,
        title="O#",
        border_line_color=None,
        location=(0, 0),
        scale_alpha=0.7,
        ticker=FixedTicker(
            ticks=[0, int(cmax / 4),
                   int(cmax / 2),
                   int(3 * cmax / 4), cmax]))
    #orientation='horizontal',location='top_left', scale_alpha=0.7)#,ticker=FixedTicker(ticks=[2,6,10,14,18]))
    p3.add_layout(color_bar3, "right")

    p4 = figure(tools=TOOLS,
                title=y[:-9] + " - Assigned Centroid MS",
                width=figdims[0],
                height=figdims[1],
                x_axis_label='m/z',
                y_axis_label='Abundance',
                y_range=[min(data["RA"]), max(data["RA"])],
                x_range=msxlim)
    p4.segment(x0=0, x1=800, y0=0, y1=0, line_width=1, line_color="black")
    p4.segment(x0='mz',
               y0=0,
               x1='mz',
               y1='RA',
               source=source,
               line_width=linewidth,
               line_color="black")
    p4.scatter(x='mz',
               y='RA',
               source=source,
               fill_color='black',
               line_color=None)
    hover = p4.select(dict(type=HoverTool))
    hover.tooltips = OrderedDict([('Formula', "@Formula"),
                                  ('Mass', "@mz{1.11111}"),
                                  ('Error (ppm)', "@Error{1.11}")])
    taptool = p4.select(type=TapTool)
    taptool.callback = OpenURL(url=url)
    p4.yaxis[0].formatter = PrintfTickFormatter(format="%4.1e")
    """
    #this is me trying to plot a barplot of heteroatomic class distributions...
    
    p7 = figure(tools=TOOLS, title=y[:-9]+"",width=800, height=600, x_axis_label='HeteroClass',y_axis_label='Count',webgl=True)
    p7.quad(left="HetClassInts",y=hetclassdf[0],source=source,width=5,height=)
    
    t7 = layouts.Column(hist)
    tab7 = Panel(child=t7,title="test")
    """
    stretch = msxlim[0] * 0.1
    p5 = figure(tools=TOOLS,
                title=y[:-9] + " - Assigned Centroid MS",
                width=1400,
                height=600,
                x_axis_label='m/z',
                y_axis_label='Abundance',
                y_range=[min(data["RA"]), max(data["RA"])],
                x_range=(msxlim[0] - stretch, msxlim[1] + stretch))
    p5.segment(x0=0, x1=800, y0=0, y1=0, line_width=1, line_color="black")
    no1 = p5.segment(x0='mz',
                     y0=0,
                     x1='mz',
                     y1='RA',
                     source=nosource,
                     line_width=linewidth,
                     line_color="red",
                     legend_label="Unassigned Peaks")
    #no2 =p5.scatter(x='mz', y='RA',source=nosource,fill_color='red',line_color=None,legend_label="Unassigned Peaks")
    #p5.scatter(x='mz', y='RA',source=source,fill_color='black',line_color=None,legend_label="Assigned Peaks")
    p5.segment(x0='mz',
               y0=0,
               x1='mz',
               y1='RA',
               source=source,
               line_width=linewidth,
               line_color="black",
               legend_label="Assigned Peaks")
    iso1 = p5.segment(x0='mz',
                      y0=0,
                      x1='mz',
                      y1='RA',
                      source=isosource,
                      line_width=linewidth,
                      line_color="green",
                      legend_label="Isotologue Peaks")
    #iso2 =p5.scatter(x='mz', y='RA',source=isosource,fill_color='green',line_color=None, legend_label="Isotologue Peaks")

    hover = p5.select(dict(type=HoverTool))
    hover.tooltips = OrderedDict([('Formula', "@Formula"),
                                  ('Mass', "@mz{1.11111}"),
                                  ('Error (ppm)', "@Error{1.11}")])
    taptool = p5.select(type=TapTool)
    taptool.callback = OpenURL(url=url)
    p5.yaxis[0].formatter = PrintfTickFormatter(format="%4.1e")

    #Bokeh 2 doesnt need JS buttons thanks to interactive legends
    #js_code1 = "iso1.glyph.visible = false; iso2.glyph.visible = false; no1.glyph.visible = false; no2.glyph.visible = false;"
    #cb1 = CustomJS(code=js_code1, args=dict(iso1=iso1,iso2=iso2,no1=no1,no2=no2))
    #js_code2 = "iso1.glyph.visible = true; iso2.glyph.visible = true; no1.glyph.visible = true; no2.glyph.visible = true;"
    #cb2 = CustomJS(code=js_code2, args=dict(iso1=iso1,iso2=iso2,no1=no1,no2=no2))

    #toggleOn = Button(label="Hide", button_type="success")
    #toggleOn.js_on_click(cb1)
    #toggleOff = Button(label="Show", button_type="success")
    #toggleOn.js_on_click(cb2)

    #top = layouts.Row(toggleOn,toggleOff)
    t3 = layouts.Column(p5)
    p5.legend.location = "top_left"
    p5.legend.click_policy = "hide"
    tab3 = Panel(child=t3, title="Centroid MS with Isotopomers and No Hits")

    downloadbutton = Button(label="Download", button_type="success")
    cb3 = CustomJS(args=dict(s2=s2),
                   code="""
		var data = s2.get('data');
		var filetext = 'mz,Error,RA,Formula,HeteroClass\\n';
		for (i=0; i < data['mz'].length; i++) {
		var currRow = [data['mz'][i].toString(),
                             data['Error'][i].toString(),
        				data['RA'][i].toString(),
        				data['Formula'][i].toString(),
        				data['HeteroClass'][i].toString().concat('\\n')];
		var joined = currRow.join();
		filetext = filetext.concat(joined);
		}
		var filename = 'data_result.csv';
		var blob = new Blob([filetext], { type: 'text/csv;charset=utf-8;' });

		//addresses IE
		if (navigator.msSaveBlob) {
			navigator.msSaveBlob(blob, filename);
		}

		else {
			var link = document.createElement("a");
			link = document.createElement('a');
			link.href = URL.createObjectURL(blob);
			link.download = filename;
			link.target = "_blank";
			link.style.visibility = 'hidden';
			link.dispatchEvent(new MouseEvent('click'))
		}
	""")
    downloadbutton.js_on_event(ButtonClick, cb3)

    columns = [
        TableColumn(field="mz",
                    title="m/z",
                    formatter=NumberFormatter(format="0.00000")),
        TableColumn(field="Error",
                    title="Error (ppm)",
                    formatter=NumberFormatter(format="0.00")),
        TableColumn(field="RA", title="Abundance"),
        TableColumn(field="Formula", title="Formula"),
        TableColumn(field="HeteroClass", title="Heteroatomic Class")
    ]
    data_table = DataTable(source=s2,
                           columns=columns,
                           width=1400,
                           header_row=False,
                           fit_columns=True)
    t4 = layouts.Column(data_table, downloadbutton)
    tab4 = Panel(child=t4, title="Selected Data Table")

    cb4 = CustomJS(args=dict(s2=s2, dt=data_table),
                   code="""
        var inds = cb_obj.get('selected')['1d'].indices;
        var d1 = cb_obj.get('data');
        var d2 = s2.get('data');
        if (inds.length == 0) {
            d2['mz'] = d1['mz']
            d2['Error'] = d1['Error']
            d2['RA'] = d1['RA']
            d2['Formula'] = d1['Formula']
            d2['HeteroClass'] = d1['HeteroClass']
        }
        else if (inds.length != 0) {
            d2['mz'] = []
            d2['Error'] = []
            d2['RA'] = []
            d2['Formula'] = []
            d2['HeteroClass'] = []
            for (i = 0; i < inds.length; i++) {
                d2['mz'].push(d1['mz'][inds[i]])
                d2['Error'].push(d1['Error'][inds[i]])
                d2['RA'].push(d1['RA'][inds[i]])
                d2['Formula'].push(d1['Formula'][inds[i]])
                d2['HeteroClass'].push(d1['HeteroClass'][inds[i]])
            }
        }
        s2.trigger('change');
        dt.trigger('change');
    """)
    source.selected.js_on_change('indices', cb4)
    """
    hetclasslist = hetclassintdf["HetClass"].tolist()
    hetclasslistnew = []
    for x in hetclasslist:
        hetclasslistnew.append([x,x])
    dropdown = Dropdown(label="Dropdown button", button_type="warning", menu=hetclasslistnew)
    """

    t1 = layouts.Row(p1, p4)
    t2 = layouts.Row(p2, p3)
    t12 = layouts.Column(t1, t2)
    tab1 = Panel(child=t12, title="Main")
    tabs = Tabs(tabs=[tab1, tab3, tab4])

    for figs in [p1, p2, p3, p4, p5]:
        figs.xaxis.axis_label_text_font_size = "14pt"
        figs.xaxis.major_label_text_font_size = "14pt"
        figs.yaxis.axis_label_text_font_size = "14pt"
        figs.yaxis.major_label_text_font_size = "14pt"
        figs.title.text_font_size = "14pt"
        figs.toolbar_location = "above"

    with open(outputpath + 'templates/index.html', 'r') as f:
        template = Template(f.read())

    #js_resources = JSResources(mode='inline')
    html = file_html(tabs, (CDN, CDN),
                     "Interactive Van Krevelen Diagrams",
                     template=template)
    output_file2 = outputpath + y[:-9] + '-plot.html'
    with open(output_file2, 'w') as f:
        f.write(html)
    view(output_file2)
Exemplo n.º 7
0
        #     """)

        # bu = template.format(stt_button = stt_button)
        # div = Div(text=bu, height=300)

        stt_button.js_on_event(
            "button_click",
            CustomJS(code="""
            var recognition = new webkitSpeechRecognition();
            recognition.continuous = true;
            recognition.interimResults = true;
        
            recognition.onresult = function (e) {
                var value = "";
                for (var i = e.resultIndex; i < e.results.length; ++i) {
                    if (e.results[i].isFinal) {
                        value += e.results[i][0].transcript;
                    }
                }
                if ( value != "") {
                    document.dispatchEvent(new CustomEvent("GET_TEXT", {detail: value}));
                }
            }
            recognition.start();
            this.addclass='active'
            """))

        result = streamlit_bokeh_events(stt_button,
                                        events="GET_TEXT",
                                        key="listen",
                                        refresh_on_update=False,
Exemplo n.º 8
0
# # Save Data Button
save_data_button = Button(label=raman_languages.TEXT__SAVE_CURRENT_DATA)
save_data_button.on_click(callback_save_data_button)

# # 20180704: just another way of saving data
with open(os.path.join(__location__, 'static/js/export_to_json.js'), 'r') as f:
    export_to_json_js = f.read()

export_data_as_json_button_callback = CustomJS(args=dict(
    source=waveform_data_source, ),
                                               code=export_to_json_js)

export_data_as_json_button = Button(
    label=raman_languages.TEXT__EXPORT_CURRENT_DATA_AS_JSON)
export_data_as_json_button.js_on_event('tap',
                                       export_data_as_json_button_callback)

with open(os.path.join(__location__, 'static/js/export_to_csv.js'), 'r') as f:
    export_to_csv_js = f.read()

export_data_as_csv_button_callback = CustomJS(args=dict(
    source=waveform_data_source, ),
                                              code=export_to_csv_js)

export_data_as_csv_button = Button(
    label=raman_languages.TEXT__EXPORT_CURRENT_DATA_AS_CSV)
export_data_as_csv_button.js_on_event('tap',
                                      export_data_as_csv_button_callback)

# Load file button
with open(os.path.join(__location__, 'static/js/load_file.js'), 'r') as f:
Exemplo n.º 9
0
import streamlit as st
from bokeh.models.widgets import Button
from bokeh.models import CustomJS
from streamlit_bokeh_events import streamlit_bokeh_events

loc_button = Button(label="Get Location")
loc_button.js_on_event(
    "button_click",
    CustomJS(code="""
    navigator.geolocation.getCurrentPosition(
        (loc) => {
            document.dispatchEvent(new CustomEvent("GET_LOCATION", {detail: {lat: loc.coords.latitude, lon: loc.coords.longitude}}))
        }
    )
    """))
result = streamlit_bokeh_events(loc_button,
                                events="GET_LOCATION",
                                key="get_location",
                                refresh_on_update=False,
                                override_height=75,
                                debounce_time=0)

if result:
    if "GET_LOCATION" in result:
        st.write(result.get("GET_LOCATION"))
import streamlit as st
from bokeh.models.widgets import Button
from bokeh.models import CustomJS
from streamlit_bokeh_events import streamlit_bokeh_events
from io import StringIO
import pandas as pd

copy_button = Button(label="Get Clipboard Data")
copy_button.js_on_event(
    "button_click",
    CustomJS(code="""
    navigator.clipboard.readText().then(text => document.dispatchEvent(new CustomEvent("GET_TEXT", {detail: text})))
    """))
result = streamlit_bokeh_events(copy_button,
                                events="GET_TEXT",
                                key="get_text",
                                refresh_on_update=False,
                                override_height=75,
                                debounce_time=0)

if result:
    if "GET_TEXT" in result:
        df = pd.read_csv(StringIO(result.get("GET_TEXT")))
        st.table(df)
Exemplo n.º 11
0
def make_document(doc):
    print(doc)

    data = ColumnDataSource(dict(
        time=[],

        acc_x=[],
        acc_y=[],
        acc_z=[],
        accg_x=[],
        accg_y=[],
        accg_z=[],
        rot_a=[],
        rot_b=[],
        rot_g=[],
        rotr_a=[],
        rotr_b=[],
        rotr_g=[],

        # angle_dev=[]
    ))

    p = figure(x_axis_type="datetime", tools='pan,wheel_zoom,box_zoom,reset,save', plot_width=1100)

    p.line(x='time', y='acc_x', line_color="red", line_width=1, source=data)
    p.line(x='time', y='acc_y', line_color="green", line_width=1, source=data)
    p.line(x='time', y='acc_z', line_color="blue", line_width=1, source=data)
    p.line(x='time', y='rot_a', line_color="cyan", line_width=1, source=data)
    p.line(x='time', y='rot_b', line_color="black", line_width=1, source=data)
    p.line(x='time', y='rot_g', line_color="orange", line_width=1, source=data)

    mid_box = BoxAnnotation(left=2, right=6, fill_alpha=0.1, fill_color='blue')

    vline = Span(location=0, dimension='height', line_color='red', line_width=3)

    p.renderers.extend([vline])

    # p.add_layout(low_box)
    p.add_layout(mid_box)
    # p.add_layout(high_box)

    p.title.text = "Sitting Project Labeling Tool v0.1"
    p.xgrid[0].grid_line_color = None
    p.ygrid[0].grid_line_alpha = 0.5
    p.xaxis.axis_label = 'Time'
    p.yaxis.axis_label = 'Value'

    div = Div(width=400, height=p.plot_height, height_policy="fixed")

    ## Events with no attributes
    # p.js_on_event(events.LODStart, display_event(div))  # Start of LOD display
    # p.js_on_event(events.LODEnd, display_event(div))  # End of LOD display

    ## Events with attributes
    # point_attributes = ['x', 'y', 'sx', 'sy']  # Point events
    # wheel_attributes = point_attributes + ['delta']  # Mouse wheel event
    # pan_attributes = point_attributes + ['delta_x', 'delta_y']  # Pan event
    # pinch_attributes = point_attributes + ['scale']  # Pinch event

    point_events = [
        events.Tap,
        # events.DoubleTap, events.Press,
        # events.MouseMove, events.MouseEnter, events.MouseLeave,
        # events.PinchStart, events.PinchEnd,
        # events.PanStart, events.PanEnd,
    ]

    # for event in point_events:
    #     p.js_on_event(event, display_event(div, attributes=point_attributes))

    p.js_on_event(events.Tap, CustomJS(args=dict(vline=vline), code="""
        vline.location = cb_obj['x'];
    """))

    btn_start = Button(label="Mark as START", button_type="success")
    btn_end = Button(label="Mark as END", button_type="success")
    btn_start.js_on_event(events.ButtonClick,
                          CustomJS(args=dict(div=div, mid_box=mid_box, vline=vline), code="""
                    mid_box.left = vline.location;
                    mid_box.right = null;
                """)
                          )

    def write_csv():
        print(mid_box.left, mid_box.right)

    btn_sit1 = Button(label="cross-leg")
    btn_sit2 = Button(label="lean-right")
    btn_sit3 = Button(label="lean-back")
    # btn_sit4 = Button(label="sit4")

    btn_sit1.js_on_event(events.ButtonClick,
                        CustomJS(
                            args=dict(div=div, mid_box=mid_box, vline=vline),
                            code="""
                       mid_box.right = vline.location;
                       console.log(mid_box.left, mid_box.right, "cross-leg");
                   """)
                        )
    btn_sit2.js_on_event(events.ButtonClick,
                        CustomJS(
                            args=dict(div=div, mid_box=mid_box, vline=vline),
                            code="""
                       mid_box.right = vline.location;
                       console.log(mid_box.left, mid_box.right, "lean-right");
                   """)
                        )
    btn_sit3.js_on_event(events.ButtonClick,
                        CustomJS(
                            args=dict(div=div, mid_box=mid_box, vline=vline),
                            code="""
                       mid_box.right = vline.location;
                       console.log(mid_box.left, mid_box.right, "lean-back");
                   """)
                        )
    # btn_sit4.js_on_event(events.ButtonClick,
    #                     CustomJS(
    #                         args=dict(div=div, mid_box=mid_box, vline=vline),
    #                         code="""
    #                    mid_box.right = vline.location;
    #                    console.log(mid_box.left, mid_box.right, "sit4");
    #                """)
    #                     )

    btn_write= Button(label="Write CSV")
    btn_write.on_click(lambda : write_csv())

    # p.js_on_event(events.MouseWheel, display_event(div, attributes=wheel_attributes))
    # p.js_on_event(events.Pan, display_event(div, attributes=pan_attributes))
    # p.js_on_event(events.Pinch, display_event(div, attributes=pinch_attributes))

    doc.add_periodic_callback(lambda: update_from_sensor(data), 60)
    doc.add_root(
        column(
            row(p, div),
            row(btn_start),
            row(column(
                btn_sit1,
                btn_sit2,
                btn_sit3,
                ) )
        )
    )
Exemplo n.º 12
0
class ViewerVIWidgets(object):
    """ 
    Encapsulates Bokeh widgets, and related callbacks, used for VI
    """
    
    def __init__(self, title, viewer_cds):
        self.vi_quality_labels = [ x["label"] for x in vi_flags if x["type"]=="quality" ]
        self.vi_issue_labels = [ x["label"] for x in vi_flags if x["type"]=="issue" ]
        self.vi_issue_slabels = [ x["shortlabel"] for x in vi_flags if x["type"]=="issue" ]
        self.js_files = get_resources('js')
        self.title = title
        self.vi_countdown_toggle = None

        #- List of fields to be recorded in output csv file, contains for each field: 
        # [ field name (in VI file header), associated variable in viewer_cds.cds_metadata ]
        self.output_file_fields = []
        for file_field in vi_file_fields:
            if file_field[1] in viewer_cds.cds_metadata.data.keys() :
                self.output_file_fields.append([file_field[0], file_field[1]])

    def add_filename(self, username='******'):
        #- VI file name
        default_vi_filename = "desi-vi_"+self.title
        default_vi_filename += ("_"+username)
        default_vi_filename += ".csv"
        self.vi_filename_input = TextInput(value=default_vi_filename, title="VI file name:")


    def add_vi_issues(self, viewer_cds, widgets):
        #- Optional VI flags (issues)
        self.vi_issue_input = CheckboxGroup(labels=self.vi_issue_labels, active=[])
        vi_issue_code = self.js_files["CSVtoArray.js"] + self.js_files["save_vi.js"]
        vi_issue_code += """
            var issues = []
            for (var i=0; i<vi_issue_labels.length; i++) {
                if (vi_issue_input.active.indexOf(i) >= 0) issues.push(vi_issue_slabels[i])
            }
            if (issues.length > 0) {
                cds_metadata.data['VI_issue_flag'][ifiberslider.value] = ( issues.join('') )
            } else {
                cds_metadata.data['VI_issue_flag'][ifiberslider.value] = " "
            }
            autosave_vi_localStorage(output_file_fields, cds_metadata.data, title)
            cds_metadata.change.emit()
            """
        self.vi_issue_callback = CustomJS(
            args=dict(cds_metadata = viewer_cds.cds_metadata,
                      ifiberslider = widgets.ifiberslider,
                      vi_issue_input = self.vi_issue_input,
                      vi_issue_labels = self.vi_issue_labels,
                      vi_issue_slabels = self.vi_issue_slabels,
                      title = self.title, output_file_fields = self.output_file_fields),
                      code = vi_issue_code )
        self.vi_issue_input.js_on_click(self.vi_issue_callback)


    def add_vi_z(self, viewer_cds, widgets):
    ## TODO: z_tovi behaviour if with_vi_widget=False ..?
        #- Optional VI information on redshift
        self.vi_z_input = TextInput(value='', title="VI redshift:")
        vi_z_code = self.js_files["CSVtoArray.js"] + self.js_files["save_vi.js"]
        vi_z_code += """
            cds_metadata.data['VI_z'][ifiberslider.value]=vi_z_input.value
            autosave_vi_localStorage(output_file_fields, cds_metadata.data, title)
            cds_metadata.change.emit()
            """
        self.vi_z_callback = CustomJS(
            args=dict(cds_metadata = viewer_cds.cds_metadata,
                      ifiberslider = widgets.ifiberslider,
                      vi_z_input = self.vi_z_input,
                      title = self.title, output_file_fields=self.output_file_fields),
                      code = vi_z_code )
        self.vi_z_input.js_on_change('value', self.vi_z_callback)

        # Copy z value from redshift slider to VI
        self.z_tovi_button = Button(label='Copy z to VI')
        self.z_tovi_callback = CustomJS(
            args=dict(z_input=widgets.z_input, vi_z_input=self.vi_z_input),
            code="""
                vi_z_input.value = z_input.value
            """)
        self.z_tovi_button.js_on_event('button_click', self.z_tovi_callback)

    def add_vi_spectype(self, viewer_cds, widgets):
        #- Optional VI information on spectral type
        self.vi_category_select = Select(value=' ', title="VI spectype:", options=([' '] + vi_spectypes))
        # The default value set to ' ' as setting value='' does not seem to work well with Select.
        vi_category_code = self.js_files["CSVtoArray.js"] + self.js_files["save_vi.js"]
        vi_category_code += """
            if (vi_category_select.value == ' ') {
                cds_metadata.data['VI_spectype'][ifiberslider.value]=''
            } else {
                cds_metadata.data['VI_spectype'][ifiberslider.value]=vi_category_select.value
            }
            autosave_vi_localStorage(output_file_fields, cds_metadata.data, title)
            cds_metadata.change.emit()
            """
        self.vi_category_callback = CustomJS(
            args=dict(cds_metadata=viewer_cds.cds_metadata, 
                      ifiberslider = widgets.ifiberslider,
                      vi_category_select=self.vi_category_select,
                      title=self.title, output_file_fields=self.output_file_fields),
            code=vi_category_code )
        self.vi_category_select.js_on_change('value', self.vi_category_callback)


    def add_vi_comment(self, viewer_cds, widgets):
        #- Optional VI comment
        self.vi_comment_input = TextInput(value='', title="VI comment (see guidelines):")
        vi_comment_code = self.js_files["CSVtoArray.js"] + self.js_files["save_vi.js"]
        vi_comment_code += """
            var stored_comment = (vi_comment_input.value).replace(/./g, function(char){
                if ( char==',' ) {
                    return ';'
                } else if ( char.charCodeAt(0)<=127 ) {
                    return char
                } else {
                    var char_list = ['Å','α','β','γ','δ','λ']
                    var char_replace = ['Angstrom','alpha','beta','gamma','delta','lambda']
                    for (var i=0; i<char_list.length; i++) {
                        if ( char==char_list[i] ) return char_replace[i]
                    }
                    return '?'
                }
            })
            cds_metadata.data['VI_comment'][ifiberslider.value] = stored_comment
            autosave_vi_localStorage(output_file_fields, cds_metadata.data, title)
            cds_metadata.change.emit()
            """
        self.vi_comment_callback = CustomJS(
            args=dict(cds_metadata = viewer_cds.cds_metadata,
                      ifiberslider = widgets.ifiberslider, 
                      vi_comment_input = self.vi_comment_input,
                      title=self.title, output_file_fields=self.output_file_fields),
            code=vi_comment_code )
        self.vi_comment_input.js_on_change('value',self.vi_comment_callback)

        #- List of "standard" VI comment
        self.vi_std_comment_select = Select(value=" ", title="Standard comment:", options=([' '] + vi_std_comments))
        vi_std_comment_code = """
            if (vi_std_comment_select.value != ' ') {
                if (vi_comment_input.value != '') {
                    vi_comment_input.value = vi_comment_input.value + " " + vi_std_comment_select.value
                } else {
                    vi_comment_input.value = vi_std_comment_select.value
                }
            }
            """
        self.vi_std_comment_callback = CustomJS(
            args = dict(vi_std_comment_select = self.vi_std_comment_select,
                        vi_comment_input = self.vi_comment_input),
                        code = vi_std_comment_code )
        self.vi_std_comment_select.js_on_change('value', self.vi_std_comment_callback)


    def add_vi_quality(self, viewer_cds, widgets):
        #- Main VI quality widget
        self.vi_quality_input = RadioButtonGroup(labels=self.vi_quality_labels)
        vi_quality_code = self.js_files["CSVtoArray.js"] + self.js_files["save_vi.js"]
        vi_quality_code += """
            if ( vi_quality_input.active >= 0 ) {
                cds_metadata.data['VI_quality_flag'][ifiberslider.value] = vi_quality_labels[vi_quality_input.active]
            } else {
                cds_metadata.data['VI_quality_flag'][ifiberslider.value] = "-1"
            }
            autosave_vi_localStorage(output_file_fields, cds_metadata.data, title)
            cds_metadata.change.emit()
        """
        self.vi_quality_callback = CustomJS(
            args = dict(cds_metadata = viewer_cds.cds_metadata,
                        vi_quality_input = self.vi_quality_input,
                        vi_quality_labels = self.vi_quality_labels,
                        ifiberslider = widgets.ifiberslider,
                        title=self.title, output_file_fields = self.output_file_fields),
            code=vi_quality_code )
        self.vi_quality_input.js_on_click(self.vi_quality_callback)

    def add_vi_scanner(self, viewer_cds):
        #- VI scanner name
        self.vi_name_input = TextInput(value=(viewer_cds.cds_metadata.data['VI_scanner'][0]).strip(), title="Your name (3-letter acronym):")
        vi_name_code = self.js_files["CSVtoArray.js"] + self.js_files["save_vi.js"]
        vi_name_code += """
            for (var i=0; i<(cds_metadata.data['VI_scanner']).length; i++) {
                cds_metadata.data['VI_scanner'][i]=vi_name_input.value
            }
            var newname = vi_filename_input.value
            var name_chunks = newname.split("_")
            newname = ( name_chunks.slice(0,name_chunks.length-1).join("_") ) + ("_"+vi_name_input.value+".csv")
            vi_filename_input.value = newname
            autosave_vi_localStorage(output_file_fields, cds_metadata.data, title)
            """
        self.vi_name_callback = CustomJS(
            args = dict(cds_metadata = viewer_cds.cds_metadata,
                        vi_name_input = self.vi_name_input,
                        vi_filename_input = self.vi_filename_input, title=self.title,
                        output_file_fields = self.output_file_fields),
            code=vi_name_code )
        self.vi_name_input.js_on_change('value', self.vi_name_callback)

    def add_guidelines(self):
        #- Guidelines for VI flags
        vi_guideline_txt = "<B> VI guidelines </B>"
        vi_guideline_txt += "<BR /> <B> Classification flags: </B>"
        for flag in vi_flags :
            if flag['type'] == 'quality' : vi_guideline_txt += ("<BR />&emsp;&emsp;[&emsp;"+flag['label']+"&emsp;] "+flag['description'])
        vi_guideline_txt += "<BR /> <B> Optional indications: </B>"
        for flag in vi_flags :
            if flag['type'] == 'issue' :
                vi_guideline_txt += ( "<BR />&emsp;&emsp;[&emsp;" + flag['label'] +
                                     "&emsp;(" + flag['shortlabel'] + ")&emsp;] " + flag['description'] )
        vi_guideline_txt += "<BR /> <B> Comments: </B> <BR /> 100 characters max, avoid commas (automatically replaced by semi-columns), ASCII only."
        self.vi_guideline_div = Div(text=vi_guideline_txt)

    def add_vi_storage(self, viewer_cds, widgets):
        #- Save VI info to CSV file
        self.save_vi_button = Button(label="Download VI", button_type="success")
        save_vi_code = self.js_files["FileSaver.js"] + self.js_files["CSVtoArray.js"] + self.js_files["save_vi.js"]
        save_vi_code += """
            download_vi_file(output_file_fields, cds_metadata.data, vi_filename_input.value)
            """
        self.save_vi_callback = CustomJS(
            args = dict(cds_metadata = viewer_cds.cds_metadata,
                        output_file_fields = self.output_file_fields,
                        vi_filename_input = self.vi_filename_input),
                        code=save_vi_code )
        self.save_vi_button.js_on_event('button_click', self.save_vi_callback)

        #- Recover auto-saved VI data in browser
        self.recover_vi_button = Button(label="Recover auto-saved VI", button_type="default")
        recover_vi_code = self.js_files["CSVtoArray.js"] + self.js_files["recover_autosave_vi.js"]
        self.recover_vi_callback = CustomJS(
            args = dict(title=self.title, output_file_fields=self.output_file_fields,
                        cds_metadata = viewer_cds.cds_metadata,
                        ifiber = widgets.ifiberslider.value, vi_comment_input = self.vi_comment_input,
                        vi_name_input=self.vi_name_input, vi_quality_input=self.vi_quality_input,
                        vi_issue_input=self.vi_issue_input,
                        vi_issue_slabels=self.vi_issue_slabels, vi_quality_labels=self.vi_quality_labels),
                        code = recover_vi_code )
        self.recover_vi_button.js_on_event('button_click', self.recover_vi_callback)

        #- Clear all auto-saved VI
        self.clear_vi_button = Button(label="Clear all auto-saved VI", button_type="default")
        self.clear_vi_callback = CustomJS( args = dict(), code = """
            localStorage.clear()
            """ )
        self.clear_vi_button.js_on_event('button_click', self.clear_vi_callback)

    def add_vi_table(self, viewer_cds):
        #- Show VI in a table
        vi_table_columns = [
            TableColumn(field="VI_quality_flag", title="Flag", width=40),
            TableColumn(field="VI_issue_flag", title="Opt.", width=50),
            TableColumn(field="VI_z", title="VI z", width=50),
            TableColumn(field="VI_spectype", title="VI spectype", width=150),
            TableColumn(field="VI_comment", title="VI comment", width=200)
        ]
        self.vi_table = DataTable(source=viewer_cds.cds_metadata, columns=vi_table_columns, width=500)
        self.vi_table.height = 10 * self.vi_table.row_height


    def add_countdown(self, vi_countdown):
        #- VI countdown
        assert vi_countdown > 0
        self.vi_countdown_callback = CustomJS(args=dict(vi_countdown=vi_countdown), code="""
            if ( (cb_obj.label).includes('Start') ) { // Callback doesn't do anything after countdown started
                var countDownDate = new Date().getTime() + (1000 * 60 * vi_countdown);
                var countDownLoop = setInterval(function(){
                    var now = new Date().getTime();
                    var distance = countDownDate - now;
                    if (distance<0) {
                        cb_obj.label = "Time's up !";
                        clearInterval(countDownLoop);
                    } else {
                        var days = Math.floor(distance / (1000 * 60 * 60 * 24));
                        var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
                        var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
                        var seconds = Math.floor((distance % (1000 * 60)) / 1000);
                        //var stuff = days + "d " + hours + "h " + minutes + "m " + seconds + "s ";
                        var stuff = minutes + "m " + seconds + "s ";
                        cb_obj.label = "Countdown: " + stuff;
                    }
                }, 1000);
            }
        """)
        self.vi_countdown_toggle = Toggle(label='Start countdown ('+str(vi_countdown)+' min)', active=False, button_type="success")
        self.vi_countdown_toggle.js_on_change('active', self.vi_countdown_callback)
Exemplo n.º 13
0
def main():

    st.set_page_config(page_title="Slide QR Code Generator",
                       page_icon="icon.ico",
                       layout='centered',
                       initial_sidebar_state='auto')

    # layout
    st.title('Slide QR Code Generator')

    # col1
    col1, col2, col3 = st.beta_columns(3)

    with col1:
        st.header("Step 1")
        st.subheader("Paste Data")

        copy_button = Button(label="Paste", max_width=100)
        copy_button.js_on_event(
            "button_click",
            CustomJS(code="""
        navigator.clipboard.readText().then(text => document.dispatchEvent(new CustomEvent("GET_TEXT", {detail: text})))
        """))

        result = streamlit_bokeh_events(copy_button,
                                        events="GET_TEXT",
                                        key="get_text",
                                        refresh_on_update=False,
                                        override_height=75,
                                        debounce_time=0)

    # col2
    with col2:
        st.header("Step 2")
        st.subheader("Set Configuration")

        # config
        qr_size_sb = st.slider("QR code size", 0, 100, 90)
        text_size_sb = st.slider("Label font size", 0, 20, 15)
        bg_width = st.slider("QR + label width", 0, 200, 110)
        bg_height = st.slider("QR + label height", 0, 200, 100)
        qr_pos_x_sb = st.slider("QR horizontal position", 0, 100, 10)
        qr_pos_y_sb = st.slider("QR vertical position", 0, 100, 0)
        text_pos_x_sb = st.slider("Label text horizontal position", 0, 100, 0)
        text_pos_y_sb = st.slider("Label text vertical position", 0, 100, 80)

        qr_size = qr_size_sb, qr_size_sb
        text_size = bg_width + 200, text_size_sb
        bg_size = bg_width, bg_height
        qr_pos = qr_pos_x_sb, qr_pos_y_sb
        text_pos = text_pos_x_sb, text_pos_y_sb
        kwargs = dict(qr_size=qr_size,
                      text_size=text_size,
                      bg_size=bg_size,
                      qr_pos=qr_pos,
                      text_pos=text_pos)

    # col3
    with col3:
        st.header("Step 3")
        st.subheader("Right Click & Copy")

    if result:
        if "GET_TEXT" in result:
            # df = pd.read_csv(StringIO(result.get("GET_TEXT")), header=None)
            # df = pd.DataFrame(StringIO(result.get("GET_TEXT")))

            data = result.get("GET_TEXT").split("\n")
            data = [i.rstrip() for i in data]
            df = pd.DataFrame(data)

            df.columns = ['slide_id']

            st.write()

            # df['slide_id'] = df['slide_id'].apply(lambda x:x.replace("\n",""))
            # st.write(df['slide_id'][0])
            # st.write(df['slide_id'][0])

            # logic
            col1.write(f"Total number of slides: {len(df)}")
            col1.write(df)
            l = list(df['slide_id'])
            output = engine.create_many_qr_codes(l, kwargs)
            col3.image(output)
Exemplo n.º 14
0
class ViewerWidgets(object):
    """ 
    Encapsulates Bokeh widgets, and related callbacks, that are part of prospect's GUI.
        Except for VI widgets
    """
    
    def __init__(self, plots, nspec):
        self.js_files = get_resources('js')
        self.navigation_button_width = 30
        self.z_button_width = 30
        self.plot_widget_width = (plots.plot_width+(plots.plot_height//2))//2 - 40 # used for widgets scaling
    
        #-----
        #- Ifiberslider and smoothing widgets
        # Ifiberslider's value controls which spectrum is displayed
        # These two widgets call update_plot(), later defined
        slider_end = nspec-1 if nspec > 1 else 0.5 # Slider cannot have start=end
        self.ifiberslider = Slider(start=0, end=slider_end, value=0, step=1, title='Spectrum (of '+str(nspec)+')')
        self.smootherslider = Slider(start=0, end=26, value=0, step=1.0, title='Gaussian Sigma Smooth')
        self.coaddcam_buttons = None
        self.model_select = None


    def add_navigation(self, nspec):
        #-----
        #- Navigation buttons
        self.prev_button = Button(label="<", width=self.navigation_button_width)
        self.next_button = Button(label=">", width=self.navigation_button_width)
        self.prev_callback = CustomJS(
            args=dict(ifiberslider=self.ifiberslider),
            code="""
            if(ifiberslider.value>0 && ifiberslider.end>=1) {
                ifiberslider.value--
            }
            """)
        self.next_callback = CustomJS(
            args=dict(ifiberslider=self.ifiberslider, nspec=nspec),
            code="""
            if(ifiberslider.value<nspec-1 && ifiberslider.end>=1) {
                ifiberslider.value++
            }
            """)
        self.prev_button.js_on_event('button_click', self.prev_callback)
        self.next_button.js_on_event('button_click', self.next_callback)

    def add_resetrange(self, viewer_cds, plots):
        #-----
        #- Axis reset button (superseeds the default bokeh "reset"
        self.reset_plotrange_button = Button(label="Reset X-Y range", button_type="default")
        reset_plotrange_code = self.js_files["adapt_plotrange.js"] + self.js_files["reset_plotrange.js"]
        self.reset_plotrange_callback = CustomJS(args = dict(fig=plots.fig, xmin=plots.xmin, xmax=plots.xmax, spectra=viewer_cds.cds_spectra),
                                            code = reset_plotrange_code)
        self.reset_plotrange_button.js_on_event('button_click', self.reset_plotrange_callback)


    def add_redshift_widgets(self, z, viewer_cds, plots):
        ## TODO handle "z" (same issue as viewerplots TBD)

        #-----
        #- Redshift / wavelength scale widgets
        z1 = np.floor(z*100)/100
        dz = z-z1
        self.zslider = Slider(start=-0.1, end=5.0, value=z1, step=0.01, title='Redshift rough tuning')
        self.dzslider = Slider(start=0.0, end=0.0099, value=dz, step=0.0001, title='Redshift fine-tuning')
        self.dzslider.format = "0[.]0000"
        self.z_input = TextInput(value="{:.4f}".format(z), title="Redshift value:")

        #- Observer vs. Rest frame wavelengths
        self.waveframe_buttons = RadioButtonGroup(
            labels=["Obs", "Rest"], active=0)

        self.zslider_callback  = CustomJS(
            args=dict(zslider=self.zslider, dzslider=self.dzslider, z_input=self.z_input),
            code="""
            // Protect against 1) recursive call with z_input callback;
            //   2) out-of-range zslider values (should never happen in principle)
            var z1 = Math.floor(parseFloat(z_input.value)*100) / 100
            if ( (Math.abs(zslider.value-z1) >= 0.01) &&
                 (zslider.value >= -0.1) && (zslider.value <= 5.0) ){
                 var new_z = zslider.value + dzslider.value
                 z_input.value = new_z.toFixed(4)
                }
            """)

        self.dzslider_callback  = CustomJS(
            args=dict(zslider=self.zslider, dzslider=self.dzslider, z_input=self.z_input),
            code="""
            var z = parseFloat(z_input.value)
            var z1 = Math.floor(z) / 100
            var z2 = z-z1
            if ( (Math.abs(dzslider.value-z2) >= 0.0001) &&
                 (dzslider.value >= 0.0) && (dzslider.value <= 0.0099) ){
                 var new_z = zslider.value + dzslider.value
                 z_input.value = new_z.toFixed(4)
                }
            """)

        self.zslider.js_on_change('value', self.zslider_callback)
        self.dzslider.js_on_change('value', self.dzslider_callback)

        self.z_minus_button = Button(label="<", width=self.z_button_width)
        self.z_plus_button = Button(label=">", width=self.z_button_width)
        self.z_minus_callback = CustomJS(
            args=dict(z_input=self.z_input),
            code="""
            var z = parseFloat(z_input.value)
            if(z >= -0.09) {
                z -= 0.01
                z_input.value = z.toFixed(4)
            }
            """)
        self.z_plus_callback = CustomJS(
            args=dict(z_input=self.z_input),
            code="""
            var z = parseFloat(z_input.value)
            if(z <= 4.99) {
                z += 0.01
                z_input.value = z.toFixed(4)
            }
            """)
        self.z_minus_button.js_on_event('button_click', self.z_minus_callback)
        self.z_plus_button.js_on_event('button_click', self.z_plus_callback)

        self.zreset_button = Button(label='Reset to z_pipe')
        self.zreset_callback = CustomJS(
            args=dict(z_input=self.z_input, metadata=viewer_cds.cds_metadata, ifiberslider=self.ifiberslider),
            code="""
                var ifiber = ifiberslider.value
                var z = metadata.data['Z'][ifiber]
                z_input.value = z.toFixed(4)
            """)
        self.zreset_button.js_on_event('button_click', self.zreset_callback)

        self.z_input_callback = CustomJS(
            args=dict(spectra = viewer_cds.cds_spectra,
                coaddcam_spec = viewer_cds.cds_coaddcam_spec,
                model = viewer_cds.cds_model,
                othermodel = viewer_cds.cds_othermodel,
                metadata = viewer_cds.cds_metadata,
                ifiberslider = self.ifiberslider,
                zslider = self.zslider,
                dzslider = self.dzslider,
                z_input = self.z_input,
                waveframe_buttons = self.waveframe_buttons,
                line_data = viewer_cds.cds_spectral_lines,
                lines = plots.speclines,
                line_labels = plots.specline_labels,
                zlines = plots.zoom_speclines,
                zline_labels = plots.zoom_specline_labels,
                overlap_waves = plots.overlap_waves,
                overlap_bands = plots.overlap_bands,
                fig = plots.fig
                ),
            code="""
                var z = parseFloat(z_input.value)
                if ( z >=-0.1 && z <= 5.0 ) {
                    // update zsliders only if needed (avoid recursive call)
                    z_input.value = parseFloat(z_input.value).toFixed(4)
                    var z1 = Math.floor(z*100) / 100
                    var z2 = z-z1
                    if ( Math.abs(z1-zslider.value) >= 0.01) zslider.value = parseFloat(parseFloat(z1).toFixed(2))
                    if ( Math.abs(z2-dzslider.value) >= 0.0001) dzslider.value = parseFloat(parseFloat(z2).toFixed(4))
                } else {
                    if (z_input.value < -0.1) z_input.value = (-0.1).toFixed(4)
                    if (z_input.value > 5) z_input.value = (5.0).toFixed(4)
                }

                var line_restwave = line_data.data['restwave']
                var ifiber = ifiberslider.value
                var waveshift_lines = (waveframe_buttons.active == 0) ? 1+z : 1 ;
                var waveshift_spec = (waveframe_buttons.active == 0) ? 1 : 1/(1+z) ;

                for(var i=0; i<line_restwave.length; i++) {
                    lines[i].location = line_restwave[i] * waveshift_lines
                    line_labels[i].x = line_restwave[i] * waveshift_lines
                    zlines[i].location = line_restwave[i] * waveshift_lines
                    zline_labels[i].x = line_restwave[i] * waveshift_lines
                }
                if (overlap_bands.length>0) {
                    for (var i=0; i<overlap_bands.length; i++) {
                        overlap_bands[i].left = overlap_waves[i][0] * waveshift_spec
                        overlap_bands[i].right = overlap_waves[i][1] * waveshift_spec
                    }
                }

                function shift_plotwave(cds_spec, waveshift) {
                    var data = cds_spec.data
                    var origwave = data['origwave']
                    var plotwave = data['plotwave']
                    if ( plotwave[0] != origwave[0] * waveshift ) { // Avoid redo calculation if not needed
                        for (var j=0; j<plotwave.length; j++) {
                            plotwave[j] = origwave[j] * waveshift ;
                        }
                        cds_spec.change.emit()
                    }
                }

                for(var i=0; i<spectra.length; i++) {
                    shift_plotwave(spectra[i], waveshift_spec)
                }
                if (coaddcam_spec) shift_plotwave(coaddcam_spec, waveshift_spec)

                // Update model wavelength array
                // NEW : don't shift model if othermodel is there
                if (othermodel) {
                    var zref = othermodel.data['zref'][0]
                    var waveshift_model = (waveframe_buttons.active == 0) ? (1+z)/(1+zref) : 1/(1+zref) ;
                    shift_plotwave(othermodel, waveshift_model)
                } else if (model) {
                    var zfit = 0.0
                    if(metadata.data['Z'] !== undefined) {
                        zfit = metadata.data['Z'][ifiber]
                    }
                    var waveshift_model = (waveframe_buttons.active == 0) ? (1+z)/(1+zfit) : 1/(1+zfit) ;
                    shift_plotwave(model, waveshift_model)
                }
            """)
        self.z_input.js_on_change('value', self.z_input_callback)
        self.waveframe_buttons.js_on_click(self.z_input_callback)

        self.plotrange_callback = CustomJS(
            args = dict(
                z_input=self.z_input,
                waveframe_buttons=self.waveframe_buttons,
                fig=plots.fig,
            ),
            code="""
            var z =  parseFloat(z_input.value)
            // Observer Frame
            if(waveframe_buttons.active == 0) {
                fig.x_range.start = fig.x_range.start * (1+z)
                fig.x_range.end = fig.x_range.end * (1+z)
            } else {
                fig.x_range.start = fig.x_range.start / (1+z)
                fig.x_range.end = fig.x_range.end / (1+z)
            }
            """
        )
        self.waveframe_buttons.js_on_click(self.plotrange_callback) # TODO: for record: is this related to waveframe bug? : 2 callbakcs for same click...


    def add_oii_widgets(self, plots):
        #------
        #- Zoom on the OII doublet TODO mv js code to other file
        # TODO: is there another trick than using a cds to pass the "oii_saveinfo" ?
        # TODO: optimize smoothing for autozoom (current value: 0)
        cds_oii_saveinfo = ColumnDataSource(
            {'xmin':[plots.fig.x_range.start], 'xmax':[plots.fig.x_range.end], 'nsmooth':[self.smootherslider.value]})
        self.oii_zoom_button = Button(label="OII-zoom", button_type="default")
        self.oii_zoom_callback = CustomJS(
            args = dict(z_input=self.z_input, fig=plots.fig, smootherslider=self.smootherslider,
                       cds_oii_saveinfo=cds_oii_saveinfo),
            code = """
            // Save previous setting (for the "Undo" button)
            cds_oii_saveinfo.data['xmin'] = [fig.x_range.start]
            cds_oii_saveinfo.data['xmax'] = [fig.x_range.end]
            cds_oii_saveinfo.data['nsmooth'] = [smootherslider.value]
            // Center on the middle of the redshifted OII doublet (vaccum)
            var z = parseFloat(z_input.value)
            fig.x_range.start = 3728.48 * (1+z) - 100
            fig.x_range.end = 3728.48 * (1+z) + 100
            // No smoothing (this implies a call to update_plot)
            smootherslider.value = 0
            """)
        self.oii_zoom_button.js_on_event('button_click', self.oii_zoom_callback)

        self.oii_undo_button = Button(label="Undo OII-zoom", button_type="default")
        self.oii_undo_callback = CustomJS(
            args = dict(fig=plots.fig, smootherslider=self.smootherslider, cds_oii_saveinfo=cds_oii_saveinfo),
            code = """
            fig.x_range.start = cds_oii_saveinfo.data['xmin'][0]
            fig.x_range.end = cds_oii_saveinfo.data['xmax'][0]
            smootherslider.value = cds_oii_saveinfo.data['nsmooth'][0]
            """)
        self.oii_undo_button.js_on_event('button_click', self.oii_undo_callback)


    def add_coaddcam(self, plots):
        #-----
        #- Highlight individual-arm or camera-coadded spectra
        coaddcam_labels = ["Camera-coadded", "Single-arm"]
        self.coaddcam_buttons = RadioButtonGroup(labels=coaddcam_labels, active=0)
        self.coaddcam_callback = CustomJS(
            args = dict(coaddcam_buttons = self.coaddcam_buttons,
                        list_lines=[plots.data_lines, plots.noise_lines,
                                    plots.zoom_data_lines, plots.zoom_noise_lines],
                        alpha_discrete = plots.alpha_discrete,
                        overlap_bands = plots.overlap_bands,
                        alpha_overlapband = plots.alpha_overlapband),
            code="""
            var n_lines = list_lines[0].length
            for (var i=0; i<n_lines; i++) {
                var new_alpha = 1
                if (coaddcam_buttons.active == 0 && i<n_lines-1) new_alpha = alpha_discrete
                if (coaddcam_buttons.active == 1 && i==n_lines-1) new_alpha = alpha_discrete
                for (var j=0; j<list_lines.length; j++) {
                    list_lines[j][i].glyph.line_alpha = new_alpha
                }
            }
            var new_alpha = 0
            if (coaddcam_buttons.active == 0) new_alpha = alpha_overlapband
            for (var j=0; j<overlap_bands.length; j++) {
                    overlap_bands[j].fill_alpha = new_alpha
            }
            """
        )
        self.coaddcam_buttons.js_on_click(self.coaddcam_callback)
    
    
    def add_metadata_tables(self, viewer_cds, show_zcat=True, template_dicts=None,
                           top_metadata=['TARGETID', 'EXPID']):
        """ Display object-related informations
                top_metadata: metadata to be highlighted in table_a
            
            Note: "short" CDS, with a single row, are used to fill these bokeh tables.
            When changing object, js code modifies these short CDS so that tables are updated.  
        """

        #- Sorted list of potential metadata:
        metadata_to_check = ['TARGETID', 'HPXPIXEL', 'TILEID', 'COADD_NUMEXP', 'COADD_EXPTIME', 
                             'NIGHT', 'EXPID', 'FIBER', 'CAMERA', 'MORPHTYPE']
        metadata_to_check += [ ('mag_'+x) for x in viewer_cds.phot_bands ]
        table_keys = []
        for key in metadata_to_check:
            if key in viewer_cds.cds_metadata.data.keys():
                table_keys.append(key)
            if 'NUM_'+key in viewer_cds.cds_metadata.data.keys():
                for prefix in ['FIRST','LAST','NUM']:
                    table_keys.append(prefix+'_'+key)
                    if key in top_metadata:
                        top_metadata.append(prefix+'_'+key)
        
        #- Table a: "top metadata"
        table_a_keys = [ x for x in table_keys if x in top_metadata ]
        self.shortcds_table_a, self.table_a = _metadata_table(table_a_keys, viewer_cds, table_width=600, 
                                                              shortcds_name='shortcds_table_a', selectable=True)
        #- Table b: Targeting information
        self.shortcds_table_b, self.table_b = _metadata_table(['Targeting masks'], viewer_cds, table_width=self.plot_widget_width,
                                                              shortcds_name='shortcds_table_b', selectable=True)
        #- Table(s) c/d : Other information (imaging, etc.)
        remaining_keys = [ x for x in table_keys if x not in top_metadata ]
        if len(remaining_keys) > 7:
            table_c_keys = remaining_keys[0:len(remaining_keys)//2]
            table_d_keys = remaining_keys[len(remaining_keys)//2:]
        else:
            table_c_keys = remaining_keys
            table_d_keys = None
        self.shortcds_table_c, self.table_c = _metadata_table(table_c_keys, viewer_cds, table_width=self.plot_widget_width,
                                                             shortcds_name='shortcds_table_c', selectable=False)
        if table_d_keys is None:
            self.shortcds_table_d, self.table_d = None, None
        else:
            self.shortcds_table_d, self.table_d = _metadata_table(table_d_keys, viewer_cds, table_width=self.plot_widget_width,
                                                                 shortcds_name='shortcds_table_d', selectable=False)

        #- Table z: redshift fitting information
        if show_zcat is not None :
            if template_dicts is not None : # Add other best fits
                fit_results = template_dicts[1]
                # Case of DeltaChi2 : compute it from Chi2s
                #    The "DeltaChi2" in rr fits is between best fits for a given (spectype,subtype)
                #    Convention: DeltaChi2 = -1 for the last fit.
                chi2s = fit_results['CHI2'][0]
                full_deltachi2s = np.zeros(len(chi2s))-1
                full_deltachi2s[:-1] = chi2s[1:]-chi2s[:-1]
                cdsdata = dict(Nfit = np.arange(1,len(chi2s)+1),
                                SPECTYPE = fit_results['SPECTYPE'][0],  # [0:num_best_fits] (if we want to restrict... TODO?)
                                SUBTYPE = fit_results['SUBTYPE'][0],
                                Z = [ "{:.4f}".format(x) for x in fit_results['Z'][0] ],
                                ZERR = [ "{:.4f}".format(x) for x in fit_results['ZERR'][0] ],
                                ZWARN = fit_results['ZWARN'][0],
                                CHI2 = [ "{:.1f}".format(x) for x in fit_results['CHI2'][0] ],
                                DELTACHI2 = [ "{:.1f}".format(x) for x in full_deltachi2s ])
                self.shortcds_table_z = ColumnDataSource(cdsdata, name='shortcds_table_z')
                columns_table_z = [ TableColumn(field=x, title=t, width=w) for x,t,w in [ ('Nfit','Nfit',5), ('SPECTYPE','SPECTYPE',70), ('SUBTYPE','SUBTYPE',60), ('Z','Z',50) , ('ZERR','ZERR',50), ('ZWARN','ZWARN',50), ('DELTACHI2','Δχ2(N+1/N)',70)] ]
                self.table_z = DataTable(source=self.shortcds_table_z, columns=columns_table_z,
                                         selectable=False, index_position=None, width=self.plot_widget_width)
                self.table_z.height = 3 * self.table_z.row_height
            else :
                self.shortcds_table_z, self.table_z = _metadata_table(viewer_cds.zcat_keys, viewer_cds,
                                    table_width=self.plot_widget_width, shortcds_name='shortcds_table_z', selectable=False)
        else :
            self.table_z = Div(text="Not available ")
            self.shortcds_table_z = None


    def add_specline_toggles(self, viewer_cds, plots):
        #-----
        #- Toggle lines
        self.speclines_button_group = CheckboxButtonGroup(
                labels=["Emission lines", "Absorption lines"], active=[])
        self.majorline_checkbox = CheckboxGroup(
                labels=['Show only major lines'], active=[])

        self.speclines_callback = CustomJS(
            args = dict(line_data = viewer_cds.cds_spectral_lines,
                        lines = plots.speclines,
                        line_labels = plots.specline_labels,
                        zlines = plots.zoom_speclines,
                        zline_labels = plots.zoom_specline_labels,
                        lines_button_group = self.speclines_button_group,
                        majorline_checkbox = self.majorline_checkbox),
            code="""
            var show_emission = false
            var show_absorption = false
            if (lines_button_group.active.indexOf(0) >= 0) {  // index 0=Emission in active list
                show_emission = true
            }
            if (lines_button_group.active.indexOf(1) >= 0) {  // index 1=Absorption in active list
                show_absorption = true
            }

            for(var i=0; i<lines.length; i++) {
                if ( !(line_data.data['major'][i]) && (majorline_checkbox.active.indexOf(0)>=0) ) {
                    lines[i].visible = false
                    line_labels[i].visible = false
                    zlines[i].visible = false
                    zline_labels[i].visible = false
                } else if (line_data.data['emission'][i]) {
                    lines[i].visible = show_emission
                    line_labels[i].visible = show_emission
                    zlines[i].visible = show_emission
                    zline_labels[i].visible = show_emission
                } else {
                    lines[i].visible = show_absorption
                    line_labels[i].visible = show_absorption
                    zlines[i].visible = show_absorption
                    zline_labels[i].visible = show_absorption
                }
            }
            """
        )
        self.speclines_button_group.js_on_click(self.speclines_callback)
        self.majorline_checkbox.js_on_click(self.speclines_callback)


    def add_model_select(self, viewer_cds, template_dicts, num_approx_fits, with_full_2ndfit=True):
        #------
        #- Select secondary model to display
        model_options = ['Best fit', '2nd best fit']
        for i in range(1,1+num_approx_fits) :
            ith = 'th'
            if i==1 : ith='st'
            if i==2 : ith='nd'
            if i==3 : ith='rd'
            model_options.append(str(i)+ith+' fit (approx)')
        if with_full_2ndfit is False :
            model_options.remove('2nd best fit')
        for std_template in ['QSO', 'GALAXY', 'STAR'] :
            model_options.append('STD '+std_template)
        self.model_select = Select(value=model_options[0], title="Other model (dashed curve):", options=model_options)
        model_select_code = self.js_files["interp_grid.js"] + self.js_files["smooth_data.js"] + self.js_files["select_model.js"]
        self.model_select_callback = CustomJS(
            args = dict(ifiberslider = self.ifiberslider,
                        model_select = self.model_select,
                        fit_templates=template_dicts[0],
                        cds_othermodel = viewer_cds.cds_othermodel,
                        cds_model_2ndfit = viewer_cds.cds_model_2ndfit,
                        cds_model = viewer_cds.cds_model,
                        fit_results=template_dicts[1],
                        std_templates=template_dicts[2],
                        median_spectra = viewer_cds.cds_median_spectra,
                        smootherslider = self.smootherslider,
                        z_input = self.z_input,
                        cds_metadata = viewer_cds.cds_metadata),
                        code = model_select_code)
        self.model_select.js_on_change('value', self.model_select_callback)


    def add_update_plot_callback(self, viewer_cds, plots, vi_widgets, template_dicts):
        #-----
        #- Main js code to update plots
        update_plot_code = (self.js_files["adapt_plotrange.js"] + self.js_files["interp_grid.js"] +
                            self.js_files["smooth_data.js"] + self.js_files["coadd_brz_cameras.js"] +
                            self.js_files["update_plot.js"])
        # TMP handling of template_dicts
        the_fit_results = None if template_dicts is None else template_dicts[1] # dirty
        self.update_plot_callback = CustomJS(
            args = dict(
                spectra = viewer_cds.cds_spectra,
                coaddcam_spec = viewer_cds.cds_coaddcam_spec,
                model = viewer_cds.cds_model,
                othermodel = viewer_cds.cds_othermodel,
                model_2ndfit = viewer_cds.cds_model_2ndfit,
                metadata = viewer_cds.cds_metadata,
                fit_results = the_fit_results,
                shortcds_table_z = self.shortcds_table_z,
                shortcds_table_a = self.shortcds_table_a,
                shortcds_table_b = self.shortcds_table_b,
                shortcds_table_c = self.shortcds_table_c,
                shortcds_table_d = self.shortcds_table_d,
                ifiberslider = self.ifiberslider,
                smootherslider = self.smootherslider,
                z_input = self.z_input,
                fig = plots.fig,
                imfig_source = plots.imfig_source,
                imfig_urls = plots.imfig_urls,
                model_select = self.model_select,
                vi_comment_input = vi_widgets.vi_comment_input,
                vi_std_comment_select = vi_widgets.vi_std_comment_select,
                vi_name_input = vi_widgets.vi_name_input,
                vi_quality_input = vi_widgets.vi_quality_input,
                vi_quality_labels = vi_widgets.vi_quality_labels,
                vi_issue_input = vi_widgets.vi_issue_input,
                vi_z_input = vi_widgets.vi_z_input,
                vi_category_select = vi_widgets.vi_category_select,
                vi_issue_slabels = vi_widgets.vi_issue_slabels
                ),
            code = update_plot_code
        )
        self.smootherslider.js_on_change('value', self.update_plot_callback)
        self.ifiberslider.js_on_change('value', self.update_plot_callback)
                     
                        
                     
                     
                     
                    S3.change.emit();
                    S4.change.emit();
                    S2.change.emit();
                    S5.change.emit();
                     
                     """)

button = Button(label="Delete entire noise (can't be undone)",
                button_type="success",
                callback=callback2)
button.js_on_event(events.ButtonClick, )

callback3 = CustomJS(args=dict(S1=S1, S2=S2, S3=S3, S4=S4, S5=S5, s=slider),
                     code="""
                     
                     var data1 = S1.data;
                     var data2 = S2.data;
                     var data3 = S3.data;
                     var data4 = S4.data;
                     var data5 = S5.data;
                    
                     
                           data2.RRSec_n_plus_1 = [];
                           data2.RRSec = [];
                           data2.epochTime = [];
                           data2.beatChar = [];
Exemplo n.º 16
0
def plotspectra(spectra,
                zcatalog=None,
                model=None,
                notebook=False,
                title=None):
    '''
    TODO: document
    '''

    if notebook:
        bk.output_notebook()

    #- If inputs are frames, convert to a spectra object
    if isinstance(spectra, list) and isinstance(spectra[0],
                                                desispec.frame.Frame):
        spectra = frames2spectra(spectra)
        frame_input = True
    else:
        frame_input = False

    if frame_input and title is None:
        meta = spectra.meta
        title = 'Night {} ExpID {} Spectrograph {}'.format(
            meta['NIGHT'],
            meta['EXPID'],
            meta['CAMERA'][1],
        )

    #- Gather spectra into ColumnDataSource objects for Bokeh
    nspec = spectra.num_spectra()
    cds_spectra = list()

    for band in spectra.bands:
        #- Set masked bins to NaN so that Bokeh won't plot them
        bad = (spectra.ivar[band] == 0.0) | (spectra.mask[band] != 0)
        spectra.flux[band][bad] = np.nan

        cdsdata = dict(
            origwave=spectra.wave[band].copy(),
            plotwave=spectra.wave[band].copy(),
        )

        for i in range(nspec):
            key = 'origflux' + str(i)
            cdsdata[key] = spectra.flux[band][i]

        cdsdata['plotflux'] = cdsdata['origflux0']

        cds_spectra.append(bk.ColumnDataSource(cdsdata, name=band))

    #- Reorder zcatalog to match input targets
    #- TODO: allow more than one zcatalog entry with different ZNUM per targetid
    targetids = spectra.target_ids()
    if zcatalog is not None:
        ii = np.argsort(np.argsort(targetids))
        jj = np.argsort(zcatalog['TARGETID'])
        kk = jj[ii]
        zcatalog = zcatalog[kk]

        #- That sequence of argsorts may feel like magic,
        #- so make sure we got it right
        assert np.all(zcatalog['TARGETID'] == targetids)
        assert np.all(zcatalog['TARGETID'] == spectra.fibermap['TARGETID'])

        #- Also need to re-order input model fluxes
        if model is not None:
            mwave, mflux = model
            model = mwave, mflux[kk]

    #- Gather models into ColumnDataSource objects, row matched to spectra
    if model is not None:
        mwave, mflux = model
        model_obswave = mwave.copy()
        model_restwave = mwave.copy()
        cds_model_data = dict(
            origwave=mwave.copy(),
            plotwave=mwave.copy(),
            plotflux=np.zeros(len(mwave)),
        )

        for i in range(nspec):
            key = 'origflux' + str(i)
            cds_model_data[key] = mflux[i]

        cds_model_data['plotflux'] = cds_model_data['origflux0']
        cds_model = bk.ColumnDataSource(cds_model_data)
    else:
        cds_model = None

    #- Subset of zcatalog and fibermap columns into ColumnDataSource
    target_info = list()
    for i, row in enumerate(spectra.fibermap):
        target_bit_names = ' '.join(desi_mask.names(row['DESI_TARGET']))
        txt = 'Target {}: {}'.format(row['TARGETID'], target_bit_names)
        if zcatalog is not None:
            txt += '<BR/>{} z={:.4f} ± {:.4f}  ZWARN={}'.format(
                zcatalog['SPECTYPE'][i],
                zcatalog['Z'][i],
                zcatalog['ZERR'][i],
                zcatalog['ZWARN'][i],
            )
        target_info.append(txt)

    cds_targetinfo = bk.ColumnDataSource(dict(target_info=target_info),
                                         name='targetinfo')
    if zcatalog is not None:
        cds_targetinfo.add(zcatalog['Z'], name='z')

    plot_width = 800
    plot_height = 400
    # tools = 'pan,box_zoom,wheel_zoom,undo,redo,reset,save'
    tools = 'pan,box_zoom,wheel_zoom,reset,save'
    fig = bk.figure(height=plot_height,
                    width=plot_width,
                    title=title,
                    tools=tools,
                    toolbar_location='above',
                    y_range=(-10, 20))
    fig.toolbar.active_drag = fig.tools[1]  #- box zoom
    fig.toolbar.active_scroll = fig.tools[2]  #- wheel zoom
    fig.xaxis.axis_label = 'Wavelength [Å]'
    fig.yaxis.axis_label = 'Flux'
    fig.xaxis.axis_label_text_font_style = 'normal'
    fig.yaxis.axis_label_text_font_style = 'normal'
    colors = dict(b='#1f77b4', r='#d62728', z='maroon')

    data_lines = list()
    for spec in cds_spectra:
        lx = fig.line('plotwave',
                      'plotflux',
                      source=spec,
                      line_color=colors[spec.name])
        data_lines.append(lx)

    if cds_model is not None:
        model_lines = list()
        lx = fig.line('plotwave',
                      'plotflux',
                      source=cds_model,
                      line_color='black')
        model_lines.append(lx)

        legend = Legend(items=[
            ("data",
             data_lines[-1::-1]),  #- reversed to get blue as lengend entry
            ("model", model_lines),
        ])
    else:
        legend = Legend(items=[
            ("data",
             data_lines[-1::-1]),  #- reversed to get blue as lengend entry
        ])

    fig.add_layout(legend, 'center')
    fig.legend.click_policy = 'hide'  #- or 'mute'

    #- Zoom figure around mouse hover of main plot
    zoomfig = bk.figure(
        height=plot_height // 2,
        width=plot_height // 2,
        y_range=fig.y_range,
        x_range=(5000, 5100),
        # output_backend="webgl",
        toolbar_location=None,
        tools=[])

    for spec in cds_spectra:
        zoomfig.line('plotwave',
                     'plotflux',
                     source=spec,
                     line_color=colors[spec.name],
                     line_width=1,
                     line_alpha=1.0)

    if cds_model is not None:
        zoomfig.line('plotwave',
                     'plotflux',
                     source=cds_model,
                     line_color='black')

    #- Callback to update zoom window x-range
    zoom_callback = CustomJS(args=dict(zoomfig=zoomfig),
                             code="""
            zoomfig.x_range.start = cb_obj.x - 100;
            zoomfig.x_range.end = cb_obj.x + 100;
        """)

    fig.js_on_event(bokeh.events.MouseMove, zoom_callback)

    #-----
    #- Emission and absorption lines
    z = zcatalog['Z'][0] if (zcatalog is not None) else 0.0
    line_data, lines, line_labels = add_lines(fig, z=z)

    #-----
    #- Add widgets for controling plots
    z1 = np.floor(z * 100) / 100
    dz = z - z1
    zslider = Slider(start=0.0, end=4.0, value=z1, step=0.01, title='Redshift')
    dzslider = Slider(start=0.0,
                      end=0.01,
                      value=dz,
                      step=0.0001,
                      title='+ Delta redshift')
    dzslider.format = "0[.]0000"

    #- Observer vs. Rest frame wavelengths
    waveframe_buttons = RadioButtonGroup(labels=["Obs", "Rest"], active=0)

    ifiberslider = Slider(start=0, end=nspec - 1, value=0, step=1)
    if frame_input:
        ifiberslider.title = 'Fiber'
    else:
        ifiberslider.title = 'Target'

    zslider_callback = CustomJS(
        args=dict(
            spectra=cds_spectra,
            model=cds_model,
            targetinfo=cds_targetinfo,
            ifiberslider=ifiberslider,
            zslider=zslider,
            dzslider=dzslider,
            waveframe_buttons=waveframe_buttons,
            line_data=line_data,
            lines=lines,
            line_labels=line_labels,
            fig=fig,
        ),
        #- TODO: reorder to reduce duplicated code
        code="""
        var z = zslider.value + dzslider.value
        var line_restwave = line_data.data['restwave']
        var ifiber = ifiberslider.value
        var zfit = 0.0
        if(targetinfo.data['z'] != undefined) {
            zfit = targetinfo.data['z'][ifiber]
        }

        // Observer Frame
        if(waveframe_buttons.active == 0) {
            var x = 0.0
            for(var i=0; i<line_restwave.length; i++) {
                x = line_restwave[i] * (1+z)
                lines[i].location = x
                line_labels[i].x = x
            }
            for(var i=0; i<spectra.length; i++) {
                var data = spectra[i].data
                var origwave = data['origwave']
                var plotwave = data['plotwave']
                for (var j=0; j<plotwave.length; j++) {
                    plotwave[j] = origwave[j]
                }
                spectra[i].change.emit()
            }

            // Update model wavelength array
            if(model) {
                var origwave = model.data['origwave']
                var plotwave = model.data['plotwave']
                for(var i=0; i<plotwave.length; i++) {
                    plotwave[i] = origwave[i] * (1+z) / (1+zfit)
                }
                model.change.emit()
            }

        // Rest Frame
        } else {
            for(i=0; i<line_restwave.length; i++) {
                lines[i].location = line_restwave[i]
                line_labels[i].x = line_restwave[i]
            }
            for (var i=0; i<spectra.length; i++) {
                var data = spectra[i].data
                var origwave = data['origwave']
                var plotwave = data['plotwave']
                for (var j=0; j<plotwave.length; j++) {
                    plotwave[j] = origwave[j] / (1+z)
                }
                spectra[i].change.emit()
            }

            // Update model wavelength array
            if(model) {
                var origwave = model.data['origwave']
                var plotwave = model.data['plotwave']
                for(var i=0; i<plotwave.length; i++) {
                    plotwave[i] = origwave[i] / (1+zfit)
                }
                model.change.emit()
            }
        }
        """)

    zslider.js_on_change('value', zslider_callback)
    dzslider.js_on_change('value', zslider_callback)
    waveframe_buttons.js_on_click(zslider_callback)

    plotrange_callback = CustomJS(args=dict(
        zslider=zslider,
        dzslider=dzslider,
        waveframe_buttons=waveframe_buttons,
        fig=fig,
    ),
                                  code="""
        var z = zslider.value + dzslider.value
        // Observer Frame
        if(waveframe_buttons.active == 0) {
            fig.x_range.start = fig.x_range.start * (1+z)
            fig.x_range.end = fig.x_range.end * (1+z)
        } else {
            fig.x_range.start = fig.x_range.start / (1+z)
            fig.x_range.end = fig.x_range.end / (1+z)
        }
        """)
    waveframe_buttons.js_on_click(plotrange_callback)

    smootherslider = Slider(start=0,
                            end=31,
                            value=0,
                            step=1.0,
                            title='Gaussian Sigma Smooth')
    target_info_div = Div(text=target_info[0])

    #-----
    #- Toggle lines
    lines_button_group = CheckboxButtonGroup(labels=["Emission", "Absorption"],
                                             active=[])

    lines_callback = CustomJS(args=dict(line_data=line_data,
                                        lines=lines,
                                        line_labels=line_labels),
                              code="""
        var show_emission = false
        var show_absorption = false
        if (cb_obj.active.indexOf(0) >= 0) {  // index 0=Emission in active list
            show_emission = true
        }
        if (cb_obj.active.indexOf(1) >= 0) {  // index 1=Absorption in active list
            show_absorption = true
        }

        for(var i=0; i<lines.length; i++) {
            if(line_data.data['emission'][i]) {
                lines[i].visible = show_emission
                line_labels[i].visible = show_emission
            } else {
                lines[i].visible = show_absorption
                line_labels[i].visible = show_absorption
            }
        }
        """)
    lines_button_group.js_on_click(lines_callback)
    # lines_button_group.js_on_change('value', lines_callback)

    #-----
    update_plot = CustomJS(args=dict(
        spectra=cds_spectra,
        model=cds_model,
        targetinfo=cds_targetinfo,
        target_info_div=target_info_div,
        ifiberslider=ifiberslider,
        smootherslider=smootherslider,
        zslider=zslider,
        dzslider=dzslider,
        lines_button_group=lines_button_group,
        fig=fig,
    ),
                           code="""
        var ifiber = ifiberslider.value
        var nsmooth = smootherslider.value
        target_info_div.text = targetinfo.data['target_info'][ifiber]

        if(targetinfo.data['z'] != undefined) {
            var z = targetinfo.data['z'][ifiber]
            var z1 = Math.floor(z*100) / 100
            zslider.value = z1
            dzslider.value = (z - z1)
        }

        function get_y_minmax(pmin, pmax, data) {
            // copy before sorting to not impact original, and filter out NaN
            var dx = data.slice().filter(Boolean)
            dx.sort()
            var imin = Math.floor(pmin * dx.length)
            var imax = Math.floor(pmax * dx.length)
            return [dx[imin], dx[imax]]
        }

        // Smoothing kernel
        var kernel = [];
        for(var i=-2*nsmooth; i<=2*nsmooth; i++) {
            kernel.push(Math.exp(-(i**2)/(2*nsmooth)))
        }
        var kernel_offset = Math.floor(kernel.length/2)

        // Smooth plot and recalculate ymin/ymax
        // TODO: add smoother function to reduce duplicated code
        var ymin = 0.0
        var ymax = 0.0
        for (var i=0; i<spectra.length; i++) {
            var data = spectra[i].data
            var plotflux = data['plotflux']
            var origflux = data['origflux'+ifiber]
            for (var j=0; j<plotflux.length; j++) {
                if(nsmooth == 0) {
                    plotflux[j] = origflux[j]
                } else {
                    plotflux[j] = 0.0
                    var weight = 0.0
                    // TODO: speed could be improved by moving `if` out of loop
                    for (var k=0; k<kernel.length; k++) {
                        var m = j+k-kernel_offset
                        if((m >= 0) && (m < plotflux.length)) {
                            var fx = origflux[m]
                            if(fx == fx) {
                                plotflux[j] = plotflux[j] + fx * kernel[k]
                                weight += kernel[k]
                            }
                        }
                    }
                    plotflux[j] = plotflux[j] / weight
                }
            }
            spectra[i].change.emit()

            tmp = get_y_minmax(0.01, 0.99, plotflux)
            ymin = Math.min(ymin, tmp[0])
            ymax = Math.max(ymax, tmp[1])
        }

        // update model
        if(model) {
            var plotflux = model.data['plotflux']
            var origflux = model.data['origflux'+ifiber]
            for (var j=0; j<plotflux.length; j++) {
                if(nsmooth == 0) {
                    plotflux[j] = origflux[j]
                } else {
                    plotflux[j] = 0.0
                    var weight = 0.0
                    // TODO: speed could be improved by moving `if` out of loop
                    for (var k=0; k<kernel.length; k++) {
                        var m = j+k-kernel_offset
                        if((m >= 0) && (m < plotflux.length)) {
                            var fx = origflux[m]
                            if(fx == fx) {
                                plotflux[j] = plotflux[j] + fx * kernel[k]
                                weight += kernel[k]
                            }
                        }
                    }
                    plotflux[j] = plotflux[j] / weight
                }
            }
            model.change.emit()
        }

        // update y_range
        if(ymin<0) {
            fig.y_range.start = ymin * 1.4
        } else {
            fig.y_range.start = ymin * 0.6
        }
        fig.y_range.end = ymax * 1.4
    """)
    smootherslider.js_on_change('value', update_plot)
    ifiberslider.js_on_change('value', update_plot)

    #-----
    #- Add navigation buttons
    navigation_button_width = 30
    prev_button = Button(label="<", width=navigation_button_width)
    next_button = Button(label=">", width=navigation_button_width)

    prev_callback = CustomJS(args=dict(ifiberslider=ifiberslider),
                             code="""
        if(ifiberslider.value>0) {
            ifiberslider.value--
        }
        """)
    next_callback = CustomJS(args=dict(ifiberslider=ifiberslider, nspec=nspec),
                             code="""
        if(ifiberslider.value<nspec+1) {
            ifiberslider.value++
        }
        """)

    prev_button.js_on_event('button_click', prev_callback)
    next_button.js_on_event('button_click', next_callback)

    #-----
    slider_width = plot_width - 2 * navigation_button_width
    navigator = bk.Row(
        widgetbox(prev_button, width=navigation_button_width),
        widgetbox(next_button, width=navigation_button_width + 20),
        widgetbox(ifiberslider, width=slider_width - 20))
    bk.show(
        bk.Column(
            bk.Row(fig, zoomfig),
            widgetbox(target_info_div, width=plot_width),
            navigator,
            widgetbox(smootherslider, width=plot_width // 2),
            bk.Row(
                widgetbox(waveframe_buttons, width=120),
                widgetbox(zslider, width=plot_width // 2 - 60),
                widgetbox(dzslider, width=plot_width // 2 - 60),
            ),
            widgetbox(lines_button_group),
        ))
Exemplo n.º 17
0
    [row.children.append(plot) for plot in plots]
    return row


def make_tab(tab_nmb):
    if tab_nmb:
        return Panel(title='{name}'.format(name=tab_nmb), child=button)
    else:
        return Panel(title='{name}'.format(name=tab_nmb), child=get_plots())


[tabs_array.append(make_tab(tab_nmb)) for tab_nmb in range(2)]
tabs = Tabs(tabs=tabs_array)


def get_callback(val):
    return CustomJS(args=dict(val=val, tabs=tabs),
                    code="""
    if (val < 0)
        tabs.active = tabs.active + val > -1 ? tabs.active + val : tabs.tabs.length -1;
    if (val > 0)
        tabs.active = tabs.active + val < tabs.tabs.length ? tabs.active + val : 0;"""
                    )


button.js_on_event(Tap, get_callback(-1))
button.on_click(button_callback)

document = curdoc()
document.add_root(tabs)
show(tabs)
Exemplo n.º 18
0
                pdbs=pdbs)

    source.data = data


update_data()

download_data_button = Button(label="Download Current Data",
                              button_type="success")
download_data_button.js_on_event(
    events.ButtonClick,
    CustomJS(args=dict(source=source),
             code="""
        var outputData = new Object();
        for (var i = 0; i < source.data['pdbs'].length; i++) {
            outputData[source.data['gnames'][i]] = source.data['pdbs'][i]
        }
        const text = JSON.stringify(outputData);
        const blob = new Blob([text], {
            type: "text/plain;charset=utf-8;",
        });
        saveAs(blob, 'graph_pdbs.json');
        """))

inputs = WidgetBox(
    children=[scut, kcut, min_count, code_select, download_data_button])

hbox = HBox(children=[inputs, p])

# Configure hover tool and add the rectangles with the hover tool set up.
boxes = p.rect(x='r_xs',
               y='r_ys',