コード例 #1
0
    def test_callback_property_executes(self, bokeh_model_page):
        group = CheckboxGroup(labels=LABELS, css_classes=["foo"])
        group.callback = CustomJS(code=RECORD("active", "cb_obj.active"))

        page = bokeh_model_page(group)

        el = page.driver.find_element_by_css_selector(
            'div.foo div label input[value="2"]')
        el.click()

        results = page.results
        assert results['active'] == [2]

        el = page.driver.find_element_by_css_selector(
            'div.foo div label input[value="0"]')
        el.click()

        results = page.results
        assert results['active'] == [0, 2]

        el = page.driver.find_element_by_css_selector(
            'div.foo div label input[value="2"]')
        el.click()

        results = page.results
        assert results['active'] == [0]

        assert page.has_no_console_errors()
コード例 #2
0
    def test_callback_property_executes(self, bokeh_model_page):
        group = CheckboxGroup(labels=LABELS, css_classes=["foo"])
        group.callback = CustomJS(code=RECORD("active", "cb_obj.active"))

        page = bokeh_model_page(group)

        el = page.driver.find_element_by_css_selector('.foo input[value="2"]')
        el.click()

        results = page.results
        assert results['active'] == [2]

        el = page.driver.find_element_by_css_selector('.foo input[value="0"]')
        el.click()

        results = page.results
        assert results['active'] == [0, 2]

        el = page.driver.find_element_by_css_selector('.foo input[value="2"]')
        el.click()

        results = page.results
        assert results['active'] == [0]

        assert page.has_no_console_errors()
コード例 #3
0
def plotting(feat1, feat2, playlists):
    '''Plot the two features feat1 & feat2 for all playlists in dictionary "playlists"

    Arguments
    --------
    feat1 = str, feature 1
    feat2 = str, feature 2
    playlists = dictionary of playlist names and song feature object returned by spotifyuser.get_features_playlist()

    Returns
    -------
    Bokeh plot with hover, reset and checkbox  ability.
    '''
    hover = HoverTool(tooltips=[("Name", "@name"), ("Artist", "@artist")])

    q = figure(plot_width=600,
               plot_height=600,
               tools=[hover, ResetTool()],
               title="Feature Plot",
               x_axis_label=feat1,
               y_axis_label=feat2)

    dots = collections.OrderedDict()
    labels = []
    active = []
    counter = 0
    for key in playlists:
        dots["scat_%02d"%counter] = q.circle(feat1, feat2, size=5, source=ColumnDataSource(playlists[key]), \
                                                color= cscheme[counter %8], legend = key, alpha = 1.0)
        labels.append(key)
        active.append(counter)
        counter += 1

    #Create code for checkbox
    code_block = "%s.visible = %s in checkbox.active;\
    "

    code = ""
    counter = 0
    for key in dots:
        code = code + (code_block % (key, str(counter)))
        counter += 1
    code = code + "show(checkbox.active)"

    #Create checkbox object
    checkbox = CheckboxGroup(labels=labels, active=active, width=100)
    args = dots
    args["checkbox"] = checkbox
    #checkbox.callback = CustomJS(args=args, lang="coffeescript", code=code)
    checkbox.callback = CustomJS(args=args, code=code)

    layout = row(q, checkbox)
    show(layout)
コード例 #4
0
ファイル: line_on_off.py プロジェクト: zoumingwei/bokeh
"""

import numpy as np

from bokeh.io import output_file, show
from bokeh.layouts import row
from bokeh.palettes import Viridis3
from bokeh.plotting import figure
from bokeh.models import CheckboxGroup, CustomJS

output_file("line_on_off.html", title="line_on_off.py example")

p = figure()
props = dict(line_width=4, line_alpha=0.7)
x = np.linspace(0, 4 * np.pi, 100)
l0 = p.line(x, np.sin(x), color=Viridis3[0], legend_label="Line 0", **props)
l1 = p.line(x, 4 * np.cos(x), color=Viridis3[1], legend_label="Line 1", **props)
l2 = p.line(x, np.tan(x), color=Viridis3[2], legend_label="Line 2", **props)

checkbox = CheckboxGroup(labels=["Line 0", "Line 1", "Line 2"],
                         active=[0, 1, 2], width=100)
checkbox.callback = CustomJS(args=dict(l0=l0, l1=l1, l2=l2, checkbox=checkbox), code="""
l0.visible = 0 in checkbox.active;
l1.visible = 1 in checkbox.active;
l2.visible = 2 in checkbox.active;
""")

layout = row(checkbox, p)
show(layout)
コード例 #5
0
ファイル: visualize.py プロジェクト: npmhung/invoice_utils
def render_mask(img_path,
                document_objs,
                document_name='Default_Document',
                output_path='./outputs/',
                save_html=False):
    img = load_img(img_path)
    bokeh.plotting.reset_output()
    hover = HoverTool(tooltips=[
        ("Name", "@name"),
        ("(x,y)", "($x, $y)"),
    ])
    fig = figure(
        tools=[hover,
               bokeh.models.WheelZoomTool(),
               bokeh.models.PanTool()])
    fig.hover.point_policy = "follow_mouse"
    fig.sizing_mode = 'scale_width'
    fig.image_url(url=[os.path.basename(img_path)],
                  x=0,
                  y=img.shape[0],
                  w=img.shape[1],
                  h=img.shape[0])

    script = "active = cb_obj.active;"
    labels = list(document_objs.keys())
    color_map = bp.magma(len(labels))

    args = dict()
    total_objs = 0
    for key_id, key in enumerate(labels):
        xs = []
        ys = []
        for box in document_objs[key]:
            _ = np.array(box).reshape(-1, 2).T
            xs.append(_[0])
            ys.append(_[1])
        ys = doccoor2planecoor(ys, img.shape[0])
        data_source = dict(
            x=xs, y=ys, name=["%s %d" % (key, idx) for idx in range(len(xs))])

        falpha = 0.5 * int('table' not in key.lower())
        lcolor = 'blue' if 'table' in key.lower() else 'red'
        lwidth = 3 if 'table' in key.lower() else 1
        total_objs += len(document_objs[key])
        args[key] = fig.patches('x',
                                'y',
                                source=data_source,
                                fill_color=color_map[key_id],
                                fill_alpha=falpha,
                                line_color=lcolor,
                                line_width=lwidth,
                                legend=key + ': %d' % len(document_objs[key]))
        r = args[key]
        script += "\n%s.visible = active.includes(%d);" % (key, key_id)
    fig.patch([], [],
              fill_color='red',
              fill_alpha=0,
              line_color='white',
              legend='Total region: %d' % total_objs)
    fig.legend.click_policy = "hide"
    fig.legend.location = "top_left"
    checkbox = CheckboxGroup(labels=labels,
                             active=[])  #active=[*range(len(labels))])
    checkbox.callback = CustomJS(args=args, code=script)
    plt_obj = [fig]

    html = file_html(plt_obj, CDN, title=document_name)
    if save_html:
        base = os.path.join(output_path, document_name)
        if os.path.exists(base):
            shutil.rmtree(base)
        os.makedirs(base)
        shutil.copy(img_path, base)
        with open(os.path.join(base, 'main.html'), 'w') as g:
            g.write(html)

    return html
コード例 #6
0
ファイル: analysis.py プロジェクト: rocheseb/eccc
                             active=range(len(lat_ordered_sites)),
                             width=200)

    ####
    checkbox_iterable = [('p' + str(i), plots[i]) for i in N_plots] + [
        ('pcor' + str(i), corplots[i]) for i in N_corplots
    ] + [('checkbox', checkbox)]
    checkbox_code = ''.join([
        'p' + str(i) + '.visible = checkbox.active.includes(' + str(i / 2) +
        ');p' + str(i + 1) + '.visible = checkbox.active.includes(' +
        str(i / 2) + ');pcor' + str(i / 2) +
        '.visible = checkbox.active.includes(' + str(i / 2) + ');'
        for i in range(0, len(N_plots), 2)
    ])
    checkbox.callback = CustomJS(
        args={key: value
              for key, value in checkbox_iterable},
        code=checkbox_code)

    # button to uncheck all checkboxes
    clear_button = Button(label='Clear all', width=120)
    clear_button_code = """checkbox.active=[];""" + checkbox_code
    clear_button.callback = CustomJS(
        args={key: value
              for key, value in checkbox_iterable},
        code=clear_button_code)

    # button to check all checkboxes
    check_button = Button(label='Check all', width=120)
    check_button_code = """checkbox.active=""" + str(
        N_plots) + """;""" + checkbox_code
    check_button.callback = CustomJS(
コード例 #7
0
def create_plot(units, df_list):
    tools = "pan,box_zoom,reset"
    p = figure(x_axis_type='datetime', tools=tools)
    p.toolbar.logo = None
    p.yaxis[0].ticker.desired_num_ticks = 4
    p.yaxis.axis_label = units
    props = dict(line_width=4, line_alpha=0.7, hover_line_alpha=1.0)
    colors = Category10[10]
    glyph_dict = {}
    labels = []
    active = []
    items = []
    sources = []
    names = 'abcdefghijklmnopqrstuvwxyz'
    callback_string = '{}.visible = {} in checkbox.active;'
    code_string = ''
    i = 0

    for df in df_list:
        legend = df.columns[0]
        series = df.iloc[:, 0]
        labels.append(legend)
        x = series.index
        y = series.values.round(2)
        source = ColumnDataSource(data={
            'x': x,
            'y': y,
            'date': [str(x) for x in x]
        })
        sources.append(source)
        line = p.line('x',
                      'y',
                      color=colors[i],
                      hover_color=colors[i],
                      source=sources[i],
                      **props)
        items.append((legend, [line]))
        name = names[i]
        line.name = name
        code_string += callback_string.format(name, str(i))
        glyph_dict.update({name: line})
        active.append(i)
        i += 1
    l = Legend(items=items,
               location=(0, 0),
               orientation='horizontal',
               border_line_color=None)
    p.add_layout(l, 'below')
    hover = HoverTool(tooltips=[('date', '@date'), ('value', '@y{0.2f}')])
    p.add_tools(hover)
    checkbox = CheckboxGroup(labels=labels, active=active, width=200)
    glyph_dict.update({'checkbox': checkbox})
    checkbox.callback = CustomJS.from_coffeescript(args=glyph_dict,
                                                   code=code_string)
    return checkbox, p


#from bokeh.layouts import row
#
#c,p = create_plot('kcfs',df_list)
#r=row([c,p])
##doc = curdoc()
##doc.theme = theme
##doc.add_root(r)
##
#show(r)
##
コード例 #8
0
ファイル: line_on_off.py プロジェクト: MulticastMatt/bokeh
"""

import numpy as np

from bokeh.io import output_file, show
from bokeh.layouts import row
from bokeh.palettes import Viridis3
from bokeh.plotting import figure
from bokeh.models import CheckboxGroup, CustomJS

output_file("line_on_off.html", title="line_on_off.py example")

p = figure()
props = dict(line_width=4, line_alpha=0.7)
x = np.linspace(0, 4 * np.pi, 100)
l0 = p.line(x, np.sin(x), color=Viridis3[0], legend="Line 0", **props)
l1 = p.line(x, 4 * np.cos(x), color=Viridis3[1], legend="Line 1", **props)
l2 = p.line(x, np.tan(x), color=Viridis3[2], legend="Line 2", **props)

checkbox = CheckboxGroup(labels=["Line 0", "Line 1", "Line 2"],
                         active=[0, 1, 2], width=100)
checkbox.callback = CustomJS(args=dict(l0=l0, l1=l1, l2=l2, checkbox=checkbox),
                             lang="coffeescript", code="""
l0.visible = 0 in checkbox.active;
l1.visible = 1 in checkbox.active;
l2.visible = 2 in checkbox.active;
""")

layout = row(checkbox, p)
show(layout)
コード例 #9
0
ファイル: visualize.py プロジェクト: npmhung/invoice_utils
def render_mask(img_path, document_objs, document_name='Default_Document', output_path='./outputs/', save_html=False):
    img = load_img(img_path)
    bokeh.plotting.reset_output()
    hover = HoverTool(
        tooltips=[
            ("Name", "@name"),
            ("(x,y)", "($x, $y)"),
        ]
    )
    fig = figure(tools=[hover,
                        bokeh.models.WheelZoomTool(),
                        bokeh.models.PanTool()])
    fig.hover.point_policy = "follow_mouse"
    fig.sizing_mode='scale_width'
    fig.image_url(url=[os.path.basename(img_path)], x=0, y=img.shape[0], w=img.shape[1], h=img.shape[0])
    
    script = "active = cb_obj.active;"
    labels = list(document_objs.keys())
    color_map = bp.magma(len(labels))
    
    args = dict()
    total_objs = 0
    for key_id, key in enumerate(labels):
        xs = []
        ys = []
        for box in document_objs[key]:
            _ = np.array(box).reshape(-1,2).T
            xs.append(_[0])
            ys.append(_[1])
        ys=doccoor2planecoor(ys, img.shape[0])
        data_source = dict(x=xs, y=ys, 
                          name=["%s %d"%(key, idx) for idx in range(len(xs))])
        
        falpha = 0.5*int('table' not in key.lower())
        lcolor = 'blue' if 'table' in key.lower() else 'red'
        lwidth = 3 if 'table' in key.lower() else 1
        total_objs += len(document_objs[key])
        args[key] = fig.patches('x', 'y', source=data_source, fill_color=color_map[key_id], 
                                fill_alpha=falpha, line_color=lcolor, line_width=lwidth, 
                                legend=key+': %d'%len(document_objs[key]))
        r = args[key]
        script += "\n%s.visible = active.includes(%d);"%(key, key_id)
    fig.patch([],[], fill_color='red', fill_alpha=0, line_color='white', legend='Total region: %d'%total_objs)
    fig.legend.click_policy="hide"
    fig.legend.location = "top_left"
    checkbox = CheckboxGroup(labels=labels, active=[])#active=[*range(len(labels))])
    checkbox.callback = CustomJS(args=args, code=script)
    plt_obj = [fig]

    
    html = file_html(plt_obj, CDN, title=document_name)
    if save_html:
        base = os.path.join(output_path, document_name)
        if os.path.exists(base):
            shutil.rmtree(base)
        os.makedirs(base)
        shutil.copy(img_path, base)
        with open(os.path.join(base, 'main.html'),'w') as g:
            g.write(html)
            
    return html
    
コード例 #10
0
ファイル: interactive_plot2.py プロジェクト: gbarl/clustering
def show_cells_on_stack(data,
                        stack,
                        X='X',
                        Y='Y',
                        channelNames=None,
                        group='group',
                        hue='hue',
                        palette='Spectral11',
                        default=0,
                        alpha=.5,
                        plot_width=500,
                        plot_height=500,
                        vmin=0,
                        vmax=3,
                        znorm=True):
    '''
    stack:  np. array of shape (nchannels,height,width)
    '''
    from bokeh.models import CheckboxGroup, RadioButtonGroup, Legend, LegendItem
    if not channelNames:
        channelNames = ['Channel ' + str(i) for i in range(len(stack))]
        print(channelNames)

    s1 = ColumnDataSource(data=data)
    p1 = figure(plot_width=plot_width,
                plot_height=plot_height,
                tools="pan,wheel_zoom,reset")

    channels = {}
    for i, channel in enumerate(channelNames):
        img = stack[i]
        if znorm:
            img = (img - img.mean()) / img.std()

        channels[i] = p1.image(image=[img],
                               x=[0],
                               y=[0],
                               dw=[plot_width],
                               dh=[plot_height],
                               color_mapper=LogColorMapper(palette=palette,
                                                           low=vmin,
                                                           high=vmax),
                               global_alpha=alpha,
                               visible=(i == default))

    plots = {}
    #scaled_coordinates to fit in stack_dw,stack_dh
    dh_ratio = plot_height / img.shape[0]
    dw_ratio = plot_width / img.shape[1]

    data['warped_X'] = data[X] * dw_ratio
    data['warped_Y'] = data[Y] * dh_ratio

    groups = list(data[group].unique())
    for g_id in groups:
        s2 = ColumnDataSource(data=data[data[group] == g_id])
        scatter = p1.circle('warped_X',
                            'warped_Y',
                            source=s2,
                            alpha=1,
                            color='hue')  #,legend_label = str(g_id))
        scatter.visible = False
        plots[g_id] = scatter

    select_celltype = CheckboxGroup(labels=groups, active=[], width=100)
    select_channel = RadioButtonGroup(labels=channelNames,
                                      active=default,
                                      width=100,
                                      orientation='horizontal')

    select_celltype.callback = CustomJS(args={
        'plots': plots,
        'groups': groups,
        'msel': select_celltype,
        'fig': p1
    },
                                        code="""
            //fig.title.text = 'new Title'
            for (var i =0; i<groups.length;i++){
               plots[groups[i]].visible = msel.active.indexOf(i)>-1
            }
               """)

    select_channel.callback = CustomJS(args={
        'channels': channels,
        'sel': select_channel,
        'fig': p1
    },
                                       code="""

        //fig.title.text = Object.keys(channels).length.toString()
        for (var i =0; i<Object.keys(channels).length;i++){
            channels[i].visible = false
        }
        var val = sel.active
        channels[val].visible = true


        /**
        if (val==0){
            fig.title.text = 'confirm upper'
            chan1.visible = true
            chan2.visible = false
            //bg_channel = [z[0]]

        }else if (val==1){
            fig.title.text = 'confirm lower'
            chan1.visible = false
            chan2.visible = true
            //bg_channel = [z[1]]

        }
        **/



    """)

    layout = column(p1, select_celltype, select_channel)
    show(layout)
コード例 #11
0
def create_charts(cur, include_8888=False):
    " Create chart on each tab for 5 regions + super DC "
    tables = create_tables(cur, for_div=True, include_8888=include_8888)
    tabs = []
    for title, code, seats in regions:
        # chart components
        p = figure(x_axis_label='滾動日期',
                   y_axis_label='支持%' if include_8888 else '有效支持%',
                   x_axis_type="datetime")
        candids = []
        earliest_date, latest_date = None, None
        for n in range(1, 30):
            candid, redness, trend = get_trend(cur, code, n, include_8888)
            if not trend: continue
            earliest_date, latest_date = trend[0][0], trend[-1][0]
            colour = getcolour(redness)
            line = p.line([d for d, _ in trend], [p for _, p in trend],
                          color=colour,
                          line_width=2,
                          line_alpha=0.9)
            label = p.text([trend[-1][0]], [trend[-1][1]],
                           text=[candid.rsplit(None, 1)[-1]],
                           text_align='right',
                           text_alpha=0.9,
                           text_baseline='bottom',
                           text_color=colour,
                           text_font_size="9pt",
                           y_offset=0.25)
            candids.append([n, candid, colour, trend[-1][1], line, label])
        if include_8888:
            candid, redness, trend = get_trend(cur, code, 8888, True)
            if not trend: continue
            earliest_date, latest_date = trend[0][0], trend[-1][0]
            line = p.line([d for d, _ in trend], [p for _, p in trend],
                          color="#707070",
                          line_width=2,
                          line_alpha=0.9)
            label = p.text([trend[-1][0]], [trend[-1][1]],
                           text=["未決定"],
                           text_align='right',
                           text_alpha=0.9,
                           text_baseline='bottom',
                           text_color="#707070",
                           text_font_size="9pt",
                           y_offset=0.25)
            candids.append([8888, "未決定", "#707070", trend[-1][1], line, label])
        p.line([earliest_date, latest_date], [100.0 / seats, 100.0 / seats],
               line_dash=[6, 3],
               color="black",
               line_width=2,
               line_alpha=0.5)
        # control
        all_lines = [n for n, _ in enumerate(candids)]
        top_5 = [
            n for _, n in sorted([(c[3], n) for n, c in enumerate(candids)],
                                 reverse=True)[:5]
        ]
        for n in all_lines:
            if n not in top_5:
                candids[n][-1].visible = candids[n][-2].visible = False
        customjs_params = [("line%d"%n, candid[-2]) for n,candid in enumerate(candids)] + \
                          [("label%d"%n, candid[-1]) for n,candid in enumerate(candids)]
        jscode = '''
            var lines = [%s];
            var labels = [%s];
            for (var n=0; n<lines.length; n++) {
                 lines[n].visible = (cb_obj.active.indexOf(n) >= 0);
                labels[n].visible = (cb_obj.active.indexOf(n) >= 0);
            };''' % (",".join("line%d" % n for n in all_lines), ",".join(
            "label%d" % n for n in all_lines))
        checkbox = CheckboxGroup(labels=[
            str(800 + c[0] if code == 'SuperDC' else c[0]) + ' ' + c[1] + ' ' +
            ("%.2f%%" % c[3]) for c in candids
        ],
                                 active=top_5)
        checkbox.callback = CustomJS(args=dict(customjs_params), code=jscode)
        # ranking table
        div = Div(text=tables[code], width=600)
        # layout and show
        layout = row(checkbox, p, div)
        tab = Panel(child=layout, title=title + "民調(" + str(seats) + '席)')
        tabs.append(tab)
    # build and return
    return Tabs(tabs=tabs)
コード例 #12
0
source_code = """
var inds = cb_obj.selected['1d'].indices;


checkbox.active = inds;


checkbox.change.emit()
"""

checkbox_code = """
source.selected['1d'].indices = cb_obj.active;
"""

button_code = """
console.log('checkbox',checkbox.active);
console.log('source',source.selected['1d'].indices);
"""

source.callback = CustomJS(args=dict(checkbox=checkbox), code=source_code)

checkbox.callback = CustomJS(args=dict(table=data_table, source=source),
                             code=checkbox_code)

button.callback = CustomJS(args=dict(table=data_table,
                                     checkbox=checkbox,
                                     source=source),
                           code=button_code)

show(widgetbox(data_table, checkbox, button))
コード例 #13
0
 checkbox.callback = CustomJS.from_coffeescript(
     args=dict(pc0=pc[0],
               pc1=pc[1],
               pc2=pc[2],
               pc3=pc[3],
               pc4=pc[4],
               pc5=pc[5],
               pc6=pc[6],
               pc7=pc[7],
               pc8=pc[8],
               pc9=pc[9],
               pc10=pc[10],
               pc11=pc[11],
               pc12=pc[12],
               pc13=pc[13],
               pc14=pc[14],
               pc15=pc[15],
               pc16=pc[16],
               pc17=pc[17],
               pc18=pc[18],
               pc19=pc[19],
               pc20=pc[20],
               pc21=pc[21],
               pc22=pc[22],
               pc23=pc[23],
               pc24=pc[24],
               pc25=pc[25],
               pc26=pc[26],
               checkbox=checkbox),
     code=''.join([
         'pc' + str(indp) + '.visible = ' + str(indp) +
         ' in checkbox.active;' for indp in range(27)
     ]))
コード例 #14
0
ファイル: main.py プロジェクト: rocheseb/tccon
def doc_maker():
    '''
	make the whole document
	'''

    global spt_data, custom_path

    curdoc().clear()  # removes everything in the current document

    # dropdown to select a spectrum
    select_spectrum = Select(title="Select a spectrum:",
                             value='',
                             options=[''] + sorted(os.listdir(spec_path)),
                             name="select_spectrum",
                             width=200)

    # textinput to give the full path to the location of spectra
    path_input = TextInput(title='Spectra folder',
                           width=200,
                           name="path_input")
    path_input.on_change('value', update_spec_path)

    # button to load the spectrum selected in the 'select_spectrum' dropdown
    load_button = Button(label='Load spectrum',
                         width=200,
                         css_classes=["custom_button"])
    load_button.on_click(load_spectrum)

    if spt_data == {}:
        curdoc().add_root(widgetbox(path_input, select_spectrum, load_button))
        if custom_path:
            path_input.value = custom_path
        else:
            path_input.value = spec_path
        return

    spectrum = spt_data['cur_spec']

    header = spt_data[spectrum]['header']

    species = np.array([spt_data[spectrum]['columns'][var] for var in header])
    SZA = str(spt_data[spectrum]['sza'])
    zobs = str(spt_data[spectrum]['zobs'])

    freq = species[0]  # the frequency list
    tm = species[1]  # measured transmittance list
    tc = species[2]  # calculated transmittance list
    cont = species[3]  # continuum
    not_gas = 4  # number of column that are not retrieved species
    residuals = spt_data[spectrum]['resid']  # 100*(calculated - measured)
    sigma_rms = spt_data[spectrum]['rms_resid']  # sqrt(mean(residuals**2))

    # spectrum figure
    fig = figure(name="spec_fig",
                 title=spectrum + '; SZA=' + SZA + '; zobs=' + zobs +
                 'km; %resid=100*(Measured-Calculated); RMSresid=' +
                 ('%.4f' % sigma_rms) + '%',
                 plot_width=1000,
                 plot_height=400,
                 tools=TOOLS,
                 y_range=Range1d(-0.04, 1.04),
                 outline_line_alpha=0,
                 active_inspect="crosshair",
                 active_drag="box_zoom")
    # residual figure
    fig_resid = figure(name="resid_fig",
                       plot_width=1000,
                       plot_height=150,
                       x_range=fig.x_range,
                       tools=TOOLS,
                       y_range=Range1d(-3, 3),
                       outline_line_alpha=0,
                       active_inspect="crosshair",
                       active_drag="box_zoom")

    # axes labels
    fig_resid.xaxis.axis_label = u'Wavenumber (cm\u207B\u00B9)'
    fig_resid.yaxis.axis_label = '% Residuals'

    fig.yaxis.axis_label = 'Transmittance'
    #fig.xaxis.axis_label = u'Wavenumber (cm\u207B\u00B9)'

    for elem in [fig, fig_resid]:
        elem.yaxis.axis_label_text_font_size = "14pt"
        elem.yaxis.major_label_text_font_size = "13pt"

        elem.xaxis.axis_label_text_font_size = "14pt"
        elem.xaxis.major_label_text_font_size = "13pt"

    N_plots = list(
        range(len(species) - 2)
    )  # a range list from 0 to the number of plots, used by the checkbox group

    # group of checkboxes that will be used to toggle line and HoverTool visibility
    checkbox = CheckboxGroup(labels=header[3:] + ['Measured', 'Calculated'],
                             active=N_plots,
                             width=200)

    # plotting species lines
    plots = []
    for j in range(len(species) - not_gas):
        try:
            plots.append(
                fig.line(x=freq,
                         y=species[j + not_gas],
                         color=colors[header[j + not_gas]],
                         line_width=2,
                         name=header[j + not_gas]))
        except KeyError:
            print(
                'KeyError:', header[j + not_gas],
                'is not specified in the "colors" dictionary, you need to add it with an associated color'
            )
            sys.exit()
        # each line has a associated hovertool with a callback that looks at the checkboxes status for the tool visibility.
        fig.add_tools(
            HoverTool(mode='vline',
                      line_policy='prev',
                      renderers=[plots[j]],
                      names=[header[j + not_gas]],
                      tooltips=OrderedDict([('name', header[j + not_gas]),
                                            ('index', '$index'),
                                            ('(x;y)', '(@x{0.00} ; @y{0.000})')
                                            ])))

    # adding the measured spectrum
    plots.append(fig.line(x=freq, y=tm, color='black', line_width=2,
                          name='Tm'))
    fig.add_tools(
        HoverTool(mode='vline',
                  line_policy='prev',
                  renderers=[plots[j + 1]],
                  names=['Tm'],
                  tooltips=OrderedDict([('name', 'Measured'),
                                        ('index', '$index'),
                                        ('(x;y)', '(@x{0.00} ; @y{0.000})')])))

    # adding the calculated spectrum
    plots.append(
        fig.line(x=freq, y=tc, color='chartreuse', line_width=2, name='Tc'))
    #fig.add_tools( HoverTool(mode='vline',line_policy='prev',renderers=[plots[j+2]],names=['Tc'],tooltips=OrderedDict( [('name','Calculated'),('index','$index'),('(x;y)','(@x{0.00} ; @y{0.000})')] )) )

    # adding the continuum
    #plots.append(fig.line(x=freq,y=cont,color='#FF3399',line_dash='dashed',line_width=2,name='Cont'))
    #fig.add_tools( HoverTool(mode='vline',line_policy='prev',renderers=[plots[j+1]],names=['Cont'],tooltips=OrderedDict( [('name','Continuum'),('index','$index'),('(x;y)','(@x{0.00} ; @y{0.000})')] )) )

    # legend outside of the figure
    fig_legend = Legend(items=[(header[j + not_gas], [plots[j]])
                               for j in range(len(species) - not_gas)] +
                        [('Measured', [plots[-2]]),
                         ('Calculated', [plots[-1]])],
                        location=(0, 0),
                        border_line_alpha=0)
    fig.add_layout(fig_legend, 'right')
    fig.legend.click_policy = "hide"
    fig.legend.inactive_fill_alpha = 0.6

    # now the residual figure
    fig_resid.line(x=freq, y=residuals, color='black', name='residuals')
    fig_resid.line(x=freq, y=np.zeros(len(freq)), color='red')
    fig_resid.add_tools(
        HoverTool(mode='vline',
                  line_policy='prev',
                  names=['residuals'],
                  tooltips={
                      'index': '$index',
                      '(x;y)': '($x{0.00} ; $y{0.000})'
                  }))

    # set up a dummy legend for the residual figure so that it aligns with the spectrum figure
    dummy = fig_resid.line(x=freq,
                           y=[0 for i in range(len(freq))],
                           color='white',
                           visible=False,
                           alpha=0)
    fig_resid_legend = Legend(items=[('               ', [dummy])],
                              location=(0, 0),
                              border_line_alpha=0)
    fig_resid.add_layout(fig_resid_legend, 'right')

    # checkbox group callback
    checkbox_iterable = [('p' + str(i), plots[i])
                         for i in N_plots] + [('checkbox', checkbox)]
    checkbox_code = ''.join([
        'p' + str(i) + '.visible = checkbox.active.includes(' + str(i) + ');'
        for i in N_plots
    ])
    checkbox.callback = CustomJS(
        args={key: value
              for key, value in checkbox_iterable},
        code=checkbox_code)

    # button to uncheck all checkboxes
    clear_button = Button(label='Hide all lines', width=200)
    clear_button_code = """checkbox.active=[];""" + checkbox_code
    clear_button.callback = CustomJS(
        args={key: value
              for key, value in checkbox_iterable},
        code=clear_button_code)

    # button to check all checkboxes
    check_button = Button(label='Show all lines', width=200)
    check_button_code = """checkbox.active=""" + str(
        N_plots) + """;""" + checkbox_code
    check_button.callback = CustomJS(
        args={key: value
              for key, value in checkbox_iterable},
        code=check_button_code)

    # extension for the saved file name based on the path to spectra
    ext = custom_path.split(os.sep)[-2]

    # title div
    div = Div(
        text='<p align="center"><font size=4><b>{}</b></font></p>'.format(ext),
        width=fig.plot_width - 100)

    add_vlinked_crosshairs(fig, fig_resid)

    sub_grid = gridplot([[fig], [fig_resid], [div]], toolbar_location="left")

    # button to activate/deactivate hover tools
    hover_button = Button(label='Enable hover tools',
                          button_type='success',
                          width=200)
    hover_list = [i for i in sub_grid.select({"type": HoverTool})]
    # in 'comp' mode, each plot has a different hover tool, I hide them and this button will click them all at once.
    hover_button_code = """
	if(cb_obj.button_type.includes("success")){
	cb_obj.button_type = 'warning';
	cb_obj.label = 'Disable hover tools'
	} else {
	cb_obj.button_type = 'success';
	cb_obj.label= 'Enable hover tools';
	}
	""" + ''.join([
        "hover{}.active = !hover{}.active;".format(i, i)
        for i in range(len(hover_list))
    ])
    hover_button.callback = CustomJS(
        args={'hover{}'.format(i): elem
              for i, elem in enumerate(hover_list)},
        code=hover_button_code)

    # put all the widgets in a box
    group = widgetbox(clear_button,
                      check_button,
                      hover_button,
                      width=200,
                      name="group")

    # the final grid for static plots
    grid = gridplot([[sub_grid, group]], toolbar_location=None)

    # save a standalone html document in spectra_app/save
    with open(os.path.join(save_path, '{}_{}.html'.format(spectrum, ext)),
              'w') as outfile:
        outfile.write(file_html(grid, CDN, spectrum[:12] + spectrum[-3:]))

    group = widgetbox(clear_button,
                      check_button,
                      hover_button,
                      path_input,
                      select_spectrum,
                      load_button,
                      width=200)

    app_grid = gridplot([[sub_grid, group]], toolbar_location=None)

    # add that grid to the document
    curdoc().add_root(app_grid)

    if custom_path:
        path_input.value = custom_path
    else:
        path_input.value = spec_path
コード例 #15
0
def bok_series(DATA, xlab='', ylab='', sup_title='', notes=''):
    """
	the DICTIONARY (or OrderedDict) DATA must be of the form:

	DATA={ 
			'lab': {
					'x':[...],
					'y':[...],
					'color':'red',
					},
			'lab2': {
					'x':[...],
					'y':[...],
					'color':'red',
					},
			'lab3': {
					'x':[...],
					'y':[...],
					'color':'red',
					},
			etc...
		 }

	if colors are not specified, the kelly_color dictionary will be used

	There will be a figure, and one "notes" text widget.
	The main figure will show all the time series

		- 'xlab' is the label of the x axis
		- 'ylab' is the label of the y axis
		- 'sup_title' is the header of the html page
		- 'notes' is a string of html code that will be displayed in a text widget beside the plots
	"""

    ######## /!\ important time handling to make sure times don't get shifted from UTC due to computer environment variables when using datetime objects ###########
    os.environ['TZ'] = 'UTC'
    time.tzset()
    # This will not change your system timezone settings
    ################################################################################################################################################################

    for label in DATA:
        try:
            test = DATA[label]['color']
        except KeyError:
            DATA[label]['color'] = kelly_colors[kelly_colors.keys()[
                DATA.keys().index(label)]]

        DATA[label]['nicetime'] = [
            dat.strftime('%d-%m-%Y %H:%M:%S') for dat in DATA[label]['x']
        ]

    if sup_title == '':
        sup_title = """<font size="4">Use the "Box Select" tool to select data of interest.</br>The table shows statistics between each dataset and the data shown in black.</font></br></br>"""

    header = Div(text=sup_title, width=700)  # the title of the dashboard

    sources = {}  # data sources for the main figure
    for label in DATA:
        sources[label] = ColumnDataSource(data={
            key: DATA[label][key]
            for key in DATA[label] if key != 'color'
        })  # 'label' data

    #get the min and max of all the data x and y
    min_x = min([DATA[label]['x'][0] for label in DATA])
    max_x = max([DATA[label]['x'][-1] for label in DATA])

    min_y = min([min(abs(DATA[label]['y'])) for label in DATA])
    max_y = max([max(DATA[label]['y']) for label in DATA])

    max_ampli = max_y - min_y

    # we will set the y axis range at +/- 10% of the data max amplitude
    min_y = min_y - max_ampli * 10 / 100
    max_y = max_y + max_ampli * 10 / 100

    TOOLS = "pan,hover,wheel_zoom,box_zoom,undo,redo,reset,save"  # interactive tools available in the html plot

    fig = figure(output_backend="webgl",
                 plot_width=900,
                 plot_height=200 + 20 * (len(DATA.keys()) - 2),
                 tools=TOOLS,
                 x_axis_type='datetime',
                 y_range=[min_y, max_y],
                 toolbar_location='left')  # figure with the time series

    # actual time series
    plots = []
    for label in DATA:
        plots.append(
            fig.scatter(x='x',
                        y='y',
                        color=DATA[label]['color'],
                        alpha=0.5,
                        source=sources[label]))

    # hover tool configuration
    fig.select_one(HoverTool).tooltips = [
        ('index', '$index'),
        ('y', '@y'),
        ('x', '@nicetime'),
    ]

    N_plots = range(len(plots))  # used in the checkbox callbacks

    # setup the legend and axis labels for the main figure
    legend = Legend(items=[(DATA.keys()[i], [plots[i]])
                           for i in range(len(DATA.keys()))],
                    location=(0, 0))
    fig.add_layout(legend, 'right')
    fig.yaxis.axis_label = ylab
    fig.xaxis.axis_label = xlab

    checkbox = CheckboxGroup(
        labels=DATA.keys(), active=range(len(DATA.keys())),
        width=100)  # the group of checkboxes, one for each 'label' in DATA

    iterable = [('p' + str(i), plots[i]) for i in N_plots] + [
        ('checkbox', checkbox)
    ]  # associate each element needed in the callback to a string

    # checkboxes to trigger line visibility
    checkbox_iterable = [('p' + str(i), plots[i])
                         for i in N_plots] + [('checkbox', checkbox)]
    checkbox_code = ''.join([
        'p' + str(i) + '.visible = checkbox.active.includes(' + str(i) + ');'
        for i in N_plots
    ])
    checkbox.callback = CustomJS(
        args={key: value
              for key, value in checkbox_iterable},
        code=checkbox_code)

    # button to uncheck all checkboxes
    clear_button = Button(label='Clear all', width=120)
    clear_button_code = """checkbox.active=[];""" + checkbox_code
    clear_button.callback = CustomJS(
        args={key: value
              for key, value in checkbox_iterable},
        code=clear_button_code)

    # button to check all checkboxes
    check_button = Button(label='Check all', width=120)
    check_button_code = """checkbox.active=""" + str(
        N_plots) + """;""" + checkbox_code
    check_button.callback = CustomJS(
        args={key: value
              for key, value in checkbox_iterable},
        code=check_button_code)

    # default text of the 'info' Div widget
    if notes == '':
        notes = """
				<font size="5"><b>Notes:</b></font></br></br>
				<font size="2">

				</font>
				"""
    dumdiv = Div(
        text='', width=50
    )  # dummy div widget to force a padding between gridplot elements

    info = Div(text=notes, width=400, height=300)  # the information Div widget

    group = widgetbox(
        checkbox, clear_button, check_button
    )  # group the checkboxes and buttons in a common "widget box"

    sub_grid = gridplot([[fig, group], [info]],
                        toolbar_location='left')  # put everything in a grid

    grid = gridplot(
        [[header], [sub_grid]], toolbar_location=None
    )  # put the previous grid under the 'header' Div widget, this is done so that the toolbar of sub_grid won't appear on the side of the header.

    return grid
コード例 #16
0
def bok_comp(DATA, select, xlab='', ylab='', sup_title='', notes='', prec='2'):
    """
	If you have data 'select' to which you want to compare several datasets 'lab0', 'lab1', etc.
	the DICTIONARY (or OrderedDict) DATA must be of the form:

	DATA={ 
			'lab': {
					'lab0':{x':[...],'y':[...]},
					'select0':{x':[...],'y':[...]},
					'color':'red',
					},
			'lab1': {
					'lab1':{x':[...],'y':[...]},
					'select1':{x':[...],'y':[...]},
					'color':'blue',
					},
			'lab2': {
					'lab2':{x':[...],'y':[...]},
					'select2':{x':[...],'y':[...]},
					'color':'orange',
					},
			etc...
		 }

	where 'select0', 'select1' etc are subsets of 'select' containing only data respectively coincident with 'lab0','lab1' etc.
	if colors are not specified, the kelly_color dictionary will be used

	There will be two figures, one table, and one "notes" text widget.
	The main figure will show all the time series of coincident data between each 'lab' and 'select'.
	The second figure will show a correlation plot including only data selected within the BoxSelect tool.
	The data in the table will also be updated based on the data selected within the BoxSelect tool.

		- 'select' is the name of the common data to which all dataset will be compared
		- 'xlab' is the label of the x axis
		- 'ylab' is the label of the y axis
		- 'sup_title' is the header of the html page
		- 'notes' is a string of html code that will be displayed in a text widget beside the plots
		- 'prec' is a "number string" that sets the precision of the values displayed in the table
	"""

    ######## /!\ important time handling to make sure times don't get shifted from UTC due to computer environment variables when using datetime objects ###########
    os.environ['TZ'] = 'UTC'
    time.tzset()
    # This will not change your system timezone settings
    ################################################################################################################################################################

    for label in DATA:
        try:
            test = DATA[label]['color']
        except KeyError:
            DATA[label]['color'] = kelly_colors[kelly_colors.keys()[
                DATA.keys().index(label)]]
        for key in DATA[label]:
            if key != 'color':
                DATA[label][key]['nicetime'] = [
                    dat.strftime('%d-%m-%Y %H:%M:%S')
                    for dat in DATA[label][key]['x']
                ]

    if sup_title == '':
        sup_title = """<font size="4">Use the "Box Select" tool to select data of interest.</br>The table shows statistics between each dataset and the data shown in black.</font></br></br>"""

    header = Div(text=sup_title, width=700)  # the title of the dashboard

    # list of columns for the table
    columns = [
        TableColumn(field='Name', title='Name'),
        TableColumn(field='N', title='N'),
        TableColumn(field='RMS', title='RMS'),
        TableColumn(field='Bias', title='Bias'),
        TableColumn(field='Scatter', title='Scatter'),
        TableColumn(field='R', title='R'),
    ]

    temp = [
        0 for i in DATA
    ]  # dummy list to initially fill teh columns of the table with zeros

    table_source = ColumnDataSource(
        data={
            'Name': DATA.keys(),
            'N': temp,
            'RMS': temp,
            'Bias': temp,
            'Scatter': temp,
            'R': temp
        })  # the data source of the table

    data_table = DataTable(source=table_source,
                           columns=columns,
                           width=450,
                           height=45 * len(DATA.keys()))  # the table itself

    txt = Div(
        text=
        'Display the table with increasing # before starting a new selection',
        width=450
    )  # text div that will be updated with the selected range of date within the BoxSelect tool

    sources = {}  # data sources for the main figure
    cor_sources = {}  # data sources for the correlation figure
    count = 0  # iterated in the for loop below and used in the sources callbacks
    for label in DATA:
        sources[label] = {
        }  # for each source 'label', there will be two time series, the 'label' data, and the coincident 'select' data
        sources[label][label] = ColumnDataSource(
            data=DATA[label][label])  # 'label' data
        sources[label][select] = ColumnDataSource(
            data=DATA[label]
            [select])  # 'select' data that is coincident with 'label' data

        cor_sources[label] = ColumnDataSource(data={
            'x': [],
            'y': []
        })  # fillable source for the correlation figure

        # give a callback to all 'label' data sources to update the correlation plot and the table based on the BoxSelect tool selection.
        sources[label][label].callback = CustomJS(
            args=dict(s2=sources[label][select],
                      dt=data_table,
                      scor=cor_sources[label]),
            code="""
		var inds = cb_obj.selected['1d'].indices;
		var d1 = cb_obj.data;
		var d2 = s2.data;
		var tab = dt.source.data;
		var dcor = scor.data;

		var difm = 0;
		var difm2 = 0;
		var scat = 0;

		var ym1 = 0;
		var ym2 = 0;

		var T1 = 0;
		var T2 = 0;
		var T3 = 0;

		dcor['x'] = [];
		dcor['y'] = [];

		tab['N'][""" + str(count) + """] = inds.length;


		if (inds.length == 0) {
			tab['RMS'][""" + str(count) + """] = 0;
			tab['Bias'][""" + str(count) + """] = 0;
			tab['Scatter'][""" + str(count) + """] = 0;
			tab['R'][""" + str(count) + """] = 0;
			dt.change.emit();
			return;
		}

		for (i=0; i < inds.length; i++){
			difm += d1['y'][inds[i]] - d2['y'][inds[i]];
			difm2 += Math.pow(d1['y'][inds[i]] - d2['y'][inds[i]],2);
			ym1 += d1['y'][inds[i]];
			ym2 += d2['y'][inds[i]];

			dcor['x'].push(d2['y'][inds[i]]);
			dcor['y'].push(d1['y'][inds[i]]);
		}

		difm /= inds.length;
		difm2 /= inds.length;
		ym1 /= inds.length;
		ym2 /= inds.length;

		for (i=0; i < inds.length; i++){
			scat += Math.pow(d1['y'][inds[i]] - d2['y'][inds[i]] - difm,2);
		}

		for (i=0; i < inds.length; i++){
			T1 += (d1['y'][inds[i]] - ym1)*(d2['y'][inds[i]] - ym2);
			T2 += Math.pow(d1['y'][inds[i]] - ym1,2);
			T3 += Math.pow(d2['y'][inds[i]] - ym2,2);
		}

		tab['RMS'][""" + str(count) + """] = Math.sqrt(difm2).toFixed(""" + prec +
            """);
		tab['Bias'][""" + str(count) + """] = difm.toFixed(""" + prec + """);
		tab['Scatter'][""" + str(count) +
            """] = Math.sqrt(scat/(inds.length -1)).toFixed(""" + prec + """);
		tab['R'][""" + str(count) + """] = (T1/Math.sqrt(T2*T3)).toFixed(""" + prec +
            """);

		dt.change.emit();
		scor.change.emit();
		""")

        count += 1

    #get the min and max of all the data x and y
    min_x = min([DATA[label][label]['x'][0] for label in DATA])
    max_x = max([DATA[label][label]['x'][-1] for label in DATA])

    min_y = min([min(abs(DATA[label][label]['y'])) for label in DATA])
    max_y = max([max(DATA[label][label]['y']) for label in DATA])

    max_ampli = max_y - min_y

    # we will set the y axis range at +/- 10% of the data max amplitude
    min_y = min_y - max_ampli * 10 / 100
    max_y = max_y + max_ampli * 10 / 100

    TOOLS = "pan,hover,wheel_zoom,box_zoom,undo,redo,reset,box_select,save"  # interactive tools available in the html plot

    fig = figure(output_backend="webgl",
                 plot_width=900,
                 plot_height=200 + 20 * (len(DATA.keys()) - 2),
                 tools=TOOLS,
                 x_axis_type='datetime',
                 y_range=[min_y, max_y],
                 toolbar_location='left')  # figure with the time series

    fig.tools[
        -2].dimensions = 'width'  # only allow the box select tool to select data along the X axis (will select all Y data in a given X range)

    UTC_offset = str(
        (datetime(*time.gmtime()[:6]) -
         datetime(*time.localtime()[:6])).seconds
    )  # machine UTC offset, javascript "Date" in the callback seems to offset the time data by the UTC offset

    # make the BoxSelect tool update the 'txt' Div widget with the currently selected range of dates.
    fig.tools[-2].callback = CustomJS(args=dict(txt=txt),
                                      code="""
		var sel = cb_data["geometry"];
		
		var startsec = sel["x0"]/1000;
		var start = new Date(0);

		start.setUTCSeconds(startsec)

		var startstring = ("0" + start.getUTCDate()).slice(-2) + "-" + ("0"+(start.getUTCMonth()+1)).slice(-2) + "-" +start.getUTCFullYear() + " " + ("0" + start.getUTCHours()).slice(-2) + ":" + ("0" + start.getUTCMinutes()).slice(-2);

		var finishsec = sel["x1"]/1000;
		var finish = new Date(0);

		finish.setUTCSeconds(finishsec)

		var finishstring = ("0" + finish.getUTCDate()).slice(-2) + "-" + ("0"+(finish.getUTCMonth()+1)).slice(-2) + "-" +finish.getUTCFullYear() + " " + ("0" + finish.getUTCHours()).slice(-2) + ":" + ("0" + finish.getUTCMinutes()).slice(-2);

		txt.text = 'Selection range from '+startstring + ' to ' + finishstring;

		txt.trigger("change"); 
		""")

    # actual time series
    plots = []
    for label in DATA:
        plots.append(
            fig.scatter(x='x',
                        y='y',
                        color=DATA[label]['color'],
                        alpha=0.5,
                        source=sources[label][label]))
        plots.append(
            fig.scatter(x='x',
                        y='y',
                        color='black',
                        alpha=0.5,
                        source=sources[label][select]))

    # hover tool configuration
    fig.select_one(HoverTool).tooltips = [
        ('index', '$index'),
        ('y', '@y'),
        ('x', '@nicetime'),
    ]

    N_plots = range(len(plots))  # used in the checkbox callbacks

    # used in the checkbox callbacks, we will trigger both 'label' and coincident 'select' data visibility at the same time
    N_plots2 = range(len(plots) / 2)
    even_plots = [i for i in N_plots if i % 2 == 0]

    # setup the legend and axis labels for the main figure
    legend = Legend(items=[(select, [plots[1]])] +
                    [(DATA.keys()[i], [plots[even_plots[i]]])
                     for i in range(len(DATA.keys()))],
                    location=(0, 0))
    fig.add_layout(legend, 'right')
    fig.yaxis.axis_label = ylab
    fig.xaxis.axis_label = xlab

    # correlation figure
    cor_fig = figure(output_backend="webgl",
                     title='Correlations',
                     plot_width=250,
                     plot_height=280,
                     x_range=[min_y, max_y],
                     y_range=[min_y, max_y])
    cor_fig.toolbar.logo = None
    cor_fig.toolbar_location = None
    cor_fig.xaxis.axis_label = ' '.join([select, ylab])
    cor_fig.yaxis.axis_label = ylab

    # one to one line in the correlation plot
    linerange = list(np.arange(0, int(max_y), ceil(max_y) / 10.0)) + [max_y]
    cor_fig.line(x=linerange, y=linerange, color='black')
    # actual correlation plots
    corplots = []
    for label in DATA:
        corplots.append(
            cor_fig.scatter(x='x',
                            y='y',
                            color=DATA[label]['color'],
                            alpha=0.5,
                            source=cor_sources[label]))

    N_corplots = range(len(corplots))  # used in the checkbox callbacks

    checkbox = CheckboxGroup(
        labels=DATA.keys(), active=range(len(DATA.keys())),
        width=100)  # the group of checkboxes, one for each 'label' in DATA

    iterable = [('p' + str(i), plots[i]) for i in N_plots] + [
        ('pcor' + str(i), corplots[i]) for i in N_corplots
    ] + [('checkbox', checkbox)
         ]  # associate each element needed in the callback to a string

    # checkboxes to trigger line visibility
    checkbox_code = """var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };"""
    checkbox_code += ''.join([
        'p' + str(i) + '.visible = indexOf.call(checkbox.active, ' +
        str(i / 2) + ') >= 0; p' + str(i + 1) +
        '.visible= indexOf.call(checkbox.active, ' + str(i / 2) +
        ') >= 0; pcor' + str(i / 2) +
        '.visible = indexOf.call(checkbox.active, ' + str(i / 2) + ') >= 0;'
        for i in range(0, len(N_plots), 2)
    ])
    checkbox.callback = CustomJS(args={key: value
                                       for key, value in iterable},
                                 code=checkbox_code)

    # button to uncheck all checkboxes
    clear_button = Button(label='Clear all', width=100)
    clear_button_code = """checkbox.set("active",[]);""" + checkbox_code
    clear_button.callback = CustomJS(
        args={key: value
              for key, value in iterable}, code=clear_button_code)

    # button to check all checkboxes
    check_button = Button(label='Check all', width=100)
    check_button_code = """checkbox.set("active",""" + str(
        N_plots2) + """);""" + checkbox_code
    check_button.callback = CustomJS(
        args={key: value
              for key, value in iterable}, code=check_button_code)

    # button to save the table data in a .csv file
    download_button = Button(label='Save Table to CSV', width=100)
    download_button.callback = CustomJS(args=dict(dt=data_table),
                                        code="""
	var tab = dt.source.data;
	var filetext = 'Name,N,RMS,Bias,Scatter,R'+String.fromCharCode(10);
	for (i=0; i < tab['Name'].length; i++) {
	    var currRow = [tab['Name'][i].toString(),
	                   tab['N'][i].toString(),
	                   tab['RMS'][i].toString(),
	                   tab['Bias'][i].toString(),
	                   tab['Scatter'][i].toString(),
	                   tab['R'][i].toString()+String.fromCharCode(10)];

	    var joined = currRow.join();
	    filetext = filetext.concat(joined);
	}

	var filename = 'data_result.csv';
	var blob = new Blob([filetext], { type: 'text/csv;charset=utf-8;' });

    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'))

	""")

    # default text of the 'info' Div widget
    if notes == '':
        notes = """
				<font size="5"><b>Notes:</b></font></br></br>
				<font size="2">
				Use the "Box Select" tool to select data of interest.</br>
				The table shows statistics between each dataset and the data shown in black.
				</font>
				"""
    dumdiv = Div(
        text='', width=50
    )  # dummy div widget to force a padding between gridplot elements

    info = Div(text=notes, width=400, height=300)  # the information Div widget

    group = widgetbox(
        checkbox, clear_button, check_button
    )  # group the checkboxes and buttons in a common "widget box"

    table_grid = gridplot(
        [[txt], [download_button], [data_table]], toolbar_location=None
    )  # group together the table, txt Div widget, and download button

    sub_grid = gridplot([[fig, group], [cor_fig, table_grid, dumdiv, info]],
                        toolbar_location='left')  # put everything in a grid

    grid = gridplot(
        [[header], [sub_grid]], toolbar_location=None
    )  # put the previous grid under the 'header' Div widget, this is done so that the toolbar of sub_grid won't appear on the side of the header.

    return grid