Beispiel #1
0
def _tap_callback(comptable_cds, div_content, io_generator):
    """
    Javacript function to animate tap events and show component info on the right

    Parameters
    ----------
    CDS: bokeh.models.ColumnDataSource
        Data structure containing a limited set of columns from the comp_table
    div: bokeh.models.Div
        Target Div element where component images will be loaded

    io_generator: tedana.io.OutputGenerator
        Output generating object for this workflow

    Returns
    -------
    CustomJS: bokeh.models.CustomJS
        Javascript function that adds the tapping functionality
    """
    return models.CustomJS(
        args=dict(
            source_comp_table=comptable_cds,
            div=div_content,
            outdir=io_generator.out_dir,
        ),
        code=tap_callback_jscode,
    )
Beispiel #2
0
def gen_upd_plot(event):
    try:
        ls_tab = []
        if inp_gen_upd.label != "Update":
            cmst_upd = get_dataset()

            for k in cmst_upd.time_selector:
                pdf_ts[k] = bmo.ColumnDataSource(data=cmst_upd.get_pandas_df(k))

                # Create panel
                ls_tab.append(create_panel(k))

            tabs = bo.layouts.column([
                bo.layouts.row([inp_xaxis, inp_yaxis]),
                bo.layouts.row([bmo.widgets.Tabs(tabs=ls_tab, width=800)]),
            ])
            l.children[-1] = tabs
            inp_gen_upd.label = "Update"

        else:
            cmst_upd = get_dataset()

            pdf_ts_upd = {}
            for k in cmst_upd.time_selector:
                pdf_ts_upd = bmo.ColumnDataSource(data=cmst_upd.get_pandas_df(k))
                pdf_ts[k].data.update(pdf_ts_upd.data)

                dct_buttons[k].callback = bmo.CustomJS(args=dict(source=pdf_ts[k], filename="{}_{}_{}.csv".format(k, inp_time_mean.value, inp_exp.value)),
                                                       code=open(join(dirname(__file__), "download.js")).read())

        hide_spinner()
    except:
        div_spinner.text="""
Beispiel #3
0
def add_callback(widget, prop):
    lines = [l1, l2, l3, l4]
    widget.callback = models.CustomJS(args=dict(widget=widget), code="""
        for ( var i = 0; i < %s; i++ ) {
            var g = eval( 'line' + i ).get( 'glyph' );
            g.set( '%s', widget.get( 'value' ) );
            window.g = g;
        }
        """ % (len(lines), prop))
    for i, line in enumerate(lines):
        widget.callback.args['line%i' % i] = line
Beispiel #4
0
    def layout(self):
        source = bkmod.AjaxDataSource(data_url=self.data_url, \
                                polling_interval=self.interval, mode='replace', method="GET")
        callback = bkmod.CustomJS(args=dict(source=source),
                                  code="""
            //console.log(source);
            var name = cb_obj.attributes.name
            if(name == "fs"){{ source.fs = cb_obj.value }}
            if(name == "f"){{ source.f = cb_obj.value }}
            // set default value
            var fs = (typeof source.fs === 'undefined') ? 1000 : source.fs;
            var f = (typeof source.f === 'undefined') ? 5 : source.f;
            source.data_url = "{}/"+fs+"/"+f;
            source.get_data('replace');
        """.format(self.data_url))

        slider_fs = bkmod.widgets.Slider(start=100,
                                         end=2000,
                                         value=1000,
                                         step=50,
                                         name="fs",
                                         callback=callback)
        slider_f = bkmod.widgets.Slider(start=1,
                                        end=20,
                                        value=5,
                                        step=1,
                                        name="f",
                                        callback=callback)
        #button = bkmod.widgets.Button(label="Update", button_type="success",callback=callback, name="update")
        #streaming=True

        source.data = dict(x=[], yn=[], y=[])

        fig = bkplt.figure(title="Streaming Example")
        if self.plot == "line":
            fig.line('x','y', source=source, legend="sine", \
                    line_color="orange", line_width=4)
            fig.line('x', 'yn', legend="sine noise", alpha=0.1, source=source)
        if self.plot == "scatter":
            fig.line('x','y', source=source, legend="sine", \
                    line_color="orange", line_width=4)
            fig.scatter('x',
                        'yn',
                        legend="sine noise",
                        alpha=0.05,
                        source=source)

        script, div = bkembed.components(bk.layouts.layout([[slider_fs,slider_f],\
                        [fig]], responsive=False, sizing_mode="scale_width")\
                , bkres.INLINE)

        plot = {"title": self.title, "plot": div, "script": script}
        return plot
def table_widget(entry):
    from bokeh.models import ColumnDataSource
    from bokeh.models.widgets import DataTable, TableColumn

    entry_dict = copy(entry.__dict__)
    print(entry_dict.keys())
    # Note: iterate over old dict, not the copy that is changing
    for k, v in entry.__dict__.items():
        if k == "id" or k == "_sa_instance_state":
            del entry_dict[k]

        # use _units keys to rename corresponding quantity
        if k[-6:] == "_units":
            prop = k[:-6]
            new_key = "{} [{}]".format(prop, entry_dict[k])
            del entry_dict[k]
            entry_dict[new_key] = entry_dict.pop(prop)

    # order entry dict
    entry_dict = OrderedDict([(k, entry_dict[k])
                              for k in sorted(list(entry_dict.keys()))])

    data = dict(
        labels=[str(k) for k in entry_dict],
        values=[str(v) for v in entry_dict.values()],
    )
    source = ColumnDataSource(data)

    columns = [
        TableColumn(field="labels", title="Properties"),
        TableColumn(field="values", title="Values"),
    ]
    data_table = DataTable(
        source=source,
        columns=columns,
        width=500,
        height=570,
        index_position=None,
        fit_columns=False,
    )

    json_str = json.dumps(entry_dict, indent=2)
    btn_download_table.callback = bmd.CustomJS(
        args=dict(string=json_str, filename=entry_dict["name"] + ".json"),
        code=download_js,
    )

    return widgetbox(data_table)
Beispiel #6
0
    def add_updated_local_time_callback(self):
        """Add callbacks to display the last-updated time in the browser-local
        timezone.
        """
        # Unfortunately, getting the timezone to show in the users's local time
        # (instead of the server timezone) was tricky - the only thing that
        # "knows" the local time is the browser, which means the updated time
        # display string has to be updated via a javascript-callback;
        # unfortunately, getting a javascript callback to fire just once, when
        # the whole graph is first built (and not when, say, the user clicks a
        # button) proved problematic - the only way I found was to make use
        # of a periodic_callback, which modified a value that a javascript
        # on change callback was watching.

        # Thanks to _jm and Bryan for their responses on this thread:
        #    https://discourse.bokeh.org/t/how-to-display-last-updated-information-in-local-time/5870

        update_time_cds = mdl.ColumnDataSource(
            data={'t': [self.model.last_update_time()]})

        update_text_cb = mdl.CustomJS(args=dict(source=update_time_cds),
                                      code="""
            var localUpdateTime = new Date(source.data['t'][0])
            cb_obj.text = "Updated: " + localUpdateTime.toString();
        """)
        self.updated.js_on_change('text', update_text_cb)

        periods_holder = [0]

        def modify_updated_time_placeholder(*args, **kwargs):
            if not self.updated.text.startswith(self.UPDATE_FETCHING):
                # print("periodic_callback removed...")
                self.doc.remove_periodic_callback(periodic_callback)
                return

            # Just cycle between values with 1 to 3 trailing "." - this just
            # makes sure that the value is always changed, so that as soon
            # as javascript is "available", the javascript "on change" callback
            # will fire.
            num_periods = periods_holder[0]
            # print("periodic_callback fired! {} - {} - {}"
            #       .format(num_periods, args, kwargs))
            periods_holder[0] = num_periods + 1
            ellipsis = '.' * (num_periods % 3 + 1)
            self.updated.text = self.UPDATE_FETCHING + ellipsis

        periodic_callback = self.doc.add_periodic_callback(
            modify_updated_time_placeholder, 1000)
def table_widget(entry):  # disable=redefined-outer-name
    """Create table widget."""
    from bokeh.models import ColumnDataSource
    from bokeh.models.widgets import DataTable, TableColumn

    entry_dict = copy(entry.__dict__)
    # Note: iterate over old dict, not the copy that is changing
    for k, _v in entry.__dict__.items():
        if k in ['id', '_sa_instance_state']:
            del entry_dict[k]

        # use _units keys to rename corresponding quantity
        if k[-6:] == '_units':
            prop = k[:-6]
            new_key = '{} [{}]'.format(prop, entry_dict[k])
            del entry_dict[k]
            entry_dict[new_key] = entry_dict.pop(prop)

    # order entry dict
    entry_dict = OrderedDict([(k, entry_dict[k])
                              for k in sorted(list(entry_dict.keys()))])

    data = dict(
        labels=[str(k) for k in entry_dict],
        values=[str(v) for v in entry_dict.values()],
    )
    source = ColumnDataSource(data)

    columns = [
        TableColumn(field='labels', title='Properties'),
        TableColumn(field='values', title='Values'),
    ]
    data_table = DataTable(source=source,
                           columns=columns,
                           width=500,
                           height=570,
                           index_position=None,
                           fit_columns=False)

    json_str = json.dumps(entry_dict, indent=2)
    btn_download_table.callback = bmd.CustomJS(args=dict(
        string=json_str, filename=entry_dict['name'] + '.json'),
                                               code=download_js)

    return widgetbox(data_table)
Beispiel #8
0
def _create_multiline_multiselect_callback(
        source: bm.ColumnDataSource) -> bm.CustomJS:

    full_source = bm.ColumnDataSource(source.data)

    callback: bm.CustomJS = bm.CustomJS(
        args=dict(source=source, full_source=full_source),
        code="""
        const indices = cb_obj.value.map(x => parseInt(x));
        let items = ['xs', 'ys', 'color', 'legend'];
        for (const item of items) {
            let full_item = full_source.data[item];
            source.data[item].length = 0;
            for (var i of indices) {
                source.data[item].push(full_item[i]);
            }
        }
        source.change.emit()
        """,
    )
    return callback
Beispiel #9
0
def create_panel(k):
    # Create plot
    p[k] = bpl.figure(tools=[TOOLS,hover],toolbar_location="right")
    p[k].circle(x=inp_xaxis.value, y=inp_yaxis.value,
                source = pdf_ts[k],
                size=12)

    p[k].xaxis.axis_label = "climate change signal {}".format(inp_xaxis.value)
    p[k].yaxis.axis_label = "climate change signal {}".format(inp_yaxis.value)

    # Horizontal line
    hline = bmo.Span(location=0, dimension='width', line_color='black', line_width=3)
    vline = bmo.Span(location=0, dimension='height', line_color='black', line_width=3)
    p[k].renderers.extend([vline, hline])

    # Create table
    columns = [
        bmo.widgets.TableColumn(field="index", title="model"),
        bmo.widgets.TableColumn(field="{}".format(inp_xaxis.value), title="{}".format(inp_xaxis.value.title()), width=65,formatter=bmo.NumberFormatter(format="0.000")),
        bmo.widgets.TableColumn(field="{}_percentiles".format(inp_xaxis.value), title="{} Perc.".format(inp_xaxis.value.title()), width=70,formatter=bmo.NumberFormatter(format="0.000")),
        bmo.widgets.TableColumn(field="{}".format(inp_yaxis.value), title="{}".format(inp_yaxis.value.title()), width=65,formatter=bmo.NumberFormatter(format="0.000")),
        bmo.widgets.TableColumn(field="{}_percentiles".format(inp_yaxis.value), title="{} Perc.".format(inp_yaxis.value.title()), width=70,formatter=bmo.NumberFormatter(format="0.000")),
    ]

    data_table = bmo.widgets.DataTable(source=pdf_ts[k], columns=columns, fit_columns=False,
                                    selectable='checkbox', height=p[k].plot_height-100, index_position=None)
    down_button = bmo.widgets.Button(label="Download CSV", button_type="primary")
    down_button.callback = bmo.CustomJS(args=dict(source=pdf_ts[k], filename="{}_{}_{}.csv".format(k, inp_time_mean.value, inp_exp.value)),
                                        code=open(join(dirname(__file__), "download.js")).read())
    dct_buttons[k] = down_button

    l_panel = bo.layouts.row([
        bo.layouts.column([p[k]]),
        bo.layouts.column([down_button, data_table]),
        ])

    panel = bmo.widgets.Panel(child=l_panel, title=time_description[k])

    return panel
Beispiel #10
0
    def build_save_button(self):
        save_button = mdl.Button(label='Save/Share', button_type="success")

        # want to have a click call python code (to calculate the url), and
        # then javascript (to do the dialog)
        # only way to do this that I found was to chain callbacks, as shown here
        # (thanks ChesuCR):
        #   https://stackoverflow.com/a/49095082/920545

        # We trigger the JS callback on a change to "tags" since that shouldn't
        # affect anything else
        js_code = r"""
            prompt("Copy the following url to save this graph:", url);
        """
        js_callback = mdl.CustomJS(code=js_code)
        save_button.js_on_change("tags", js_callback)

        def on_click():
            querystr = self.model.to_query_str()
            # TODO: don't hardcode directory portion
            host = self.doc.session_context.request.headers['Host']
            url = f'http://{host}/covid19?{querystr}'

            # we could change js_callback.code, but easier to change args
            js_callback.args = {'url': url}

            # now trigger the javascript, by changing tags
            tags = save_button.tags
            SENTINEL = 'click_toggle'
            if SENTINEL in tags:
                tags.remove(SENTINEL)
            else:
                tags.append(SENTINEL)
            # this should trigger the javascript
            save_button.tags = tags

        save_button.on_click(on_click)

        return save_button
        # j2sPath="https://www.materialscloud.org/discover/scripts/external/jsmol/j2s",
        serverURL="detail/static/jsmol/php/jsmol.php",
        j2sPath="detail/static/jsmol/j2s",
        script="""set antialiasDisplay ON;
load data "cifstring"
{}
end "cifstring"
""".format(cif_str)
        ## Note: Need PHP server for approach below to work
        #    script="""set antialiasDisplay ON;
        # load cif::{};
        # """.format(get_cif_url(entry.filename))
    )

    btn_download_cif.callback = bmd.CustomJS(args=dict(
        string=cif_str, filename=entry.filename),
                                             code=download_js)
    script_source = bmd.ColumnDataSource()

    applet = JSMol(
        width=600,
        height=600,
        script_source=script_source,
        info=info,
        js_url="detail/static/jsmol/JSmol.min.js",
    )

    df_tailcorrection, df_no_tailcorrection = get_results_df()

    if cof_name in used_block:
        plot_info_ = plot_info_blocked_pockets
Beispiel #12
0
def make_responsive_plot(prot, tag):
    #output_file("test_deg_def.html", title="line deg")
    title = tag

    fig_fit = get_base_plot(prot, title)
    #fig_fit.set(y_range=bkm.Range1d(-0.1, 1.1))
    x_lim = prot.X[-1] + 0.1
    X = np.arange(-0.1, x_lim, 0.1)

    Ys = model_syn(X, prot.N0, prot.tau, prot.offset)
    Yd = model_deg(X, prot.N0, prot.tau, prot.offset)

    params_start = [prot.N0, prot.tau, prot.offset, title]
    params = [prot.N0, prot.tau, prot.offset, title]

    diff = len(Yd) - len(params)
    add = [np.nan] * diff
    params_start += add
    params += add

    source = bkm.ColumnDataSource(data=dict(
        X=X,
        Ys=Ys,
        Yd=Yd,
        params_start=params_start,
        params=params,
    ))

    code = """
                var data = source.get('data');
                var params_start = data['params_start']
                var X = data['X'];
                var Ys = data['Ys'];
                var Yd = data['Yd'];
                var params = data['params'];

                var title = params[3];
   
                var f = cb_obj.get('value');

                if (cb_obj.get('title') == 'N0') {N0 = cb_obj.get('value'); params[0] = N0;};
                if (cb_obj.get('title') == 'tau') {tau = cb_obj.get('value'); params[1] = tau; };
                if (cb_obj.get('title') == 'offset') {offset = cb_obj.get('value'); params[2] = offset;};
                
                var N0 = parseFloat(params[0]);
                var tau = parseFloat(params[1]);
                var offset = parseFloat(params[2]);
                
                //console.log(params, 'here parms');
                //console.log(N0, 'here N0');
                //console.log(tau, 'here tau');
                //console.log(offset, 'here offset');
                
                
                //console.log(Ys, 'here Ys before');
                //console.log(Yd, 'here Yd before');                
                
                for (i = 0; i < X.length; i++) {
                    Ys[i] =  1 - ((N0 * Math.exp( -X[i]/tau )) +  offset) ;
                }
                 
                for (i = 0; i < X.length; i++) {
                    Yd[i] =  (N0 * Math.exp( -X[i]/tau )) + offset  ;
                }        
                
                
                var last_element = X[X.length - 1];
                var residual =  (N0 * Math.exp( -last_element/tau )) + offset 
                
                
                //console.log(Ys, 'here Ys after');
                //console.log(Yd, 'here Yd after');
                
                
                source.trigger('change');
                console.log(N0, 'here N0 after');
                console.log(tau, 'here tau after'); 
                console.log(offset, 'here offset after'); 
                console.log( tau / Math.log(2) ,'here half life')
                //$("field_name_1").update(tau/Math.log(2));
                //$("field_name_2").update(tau);
                //$("field_name_3").update(offset);
                
                
                $('#field_name_1').text(Math.round(tau/Math.log(2)* 100)/100);
                $('#field_name_2').text(Math.round(residual * 100)/100);
                //$('#field_name_3').text(offset);
                
                //document.getElementById("field_name_1").innerHTML = N0;
                
                 // $( ".hello" ).remove();
                //var $new = $('<div class="hello"></div>').appendTo('.insert_body');
                //http://stackoverflow.com/questions/247483/http-get-request-in-javascript
                
                //function httpGet(theUrl)
                //{
                    //var xmlHttp = new XMLHttpRequest();
                    //xmlHttp.open( "GET", theUrl, false ); // false for synchronous request
                    //xmlHttp.send( null );
                    //return xmlHttp.responseText;
                //}
                //var address = '{web_address}find_intersection?N0='+N0+'&tau='+tau+'&c='+offset
                //var res = httpGet(address);
                //console.log(res, 'test');
                
                //if (title == 'Bloodstrem'){
                        //console.log('new_intersection_bs');
                        //$("#new_intersection_bs").html('new intersection: '+res);                
                //}
                //if (title == 'Procyclic'){
                       // $("#new_intersection_pc").html('new intersection: '+res);                
                //}
                
                
                //res = httpGet(address)
                //console.log(res, 'test');
                
                //ras = $.get("address");
                //req.open('GET', address, false);    
                //
                //console.log(address);
                """

    #code = code.replace('{web_address}', web_adress)
    callback = bkm.CustomJS(args=dict(source=source), code=code)

    sliderN0 = bkm.Slider(start=0,
                          end=1,
                          value=prot.N0,
                          step=.01,
                          title="N0",
                          name='N0',
                          callback=callback)
    sliderTau = bkm.Slider(start=0.1,
                           end=50,
                           value=prot.tau,
                           step=.01,
                           title="tau",
                           name='tau',
                           callback=callback)
    sliderOffSet = bkm.Slider(start=0,
                              end=1,
                              value=prot.offset,
                              step=.01,
                              title="offset",
                              name='offset',
                              callback=callback)
    syn = fig_fit.line(x='X', y='Ys', source=source, color='green')
    deg = fig_fit.line(x='X', y='Yd', source=source, color='red')

    legend = Legend(items=[("syn", [syn]), ("deg", [deg])], location=(10, -30))
    #fig_fit.legend.location = (0, -30)
    #layout = vform(fig_fit)
    #script, div = components(layout)
    #layout =  vform()
    #script_bar, div_bar = components(layout)

    #show(layout(
    #[[fig_fit],[sliderN0],[sliderTau],[sliderOffSet]]

    #))
    fig_fit.add_layout(legend, 'right')
    #show(layouts.column(fig_fit, sliderN0, sliderTau, sliderOffSet))
    script, div = components(
        layouts.column(fig_fit, sliderN0, sliderTau, sliderOffSet))
    return script, div
Beispiel #13
0
                             value="tasmax",
                             options=["tasmin", "tasmax", "pr", "rsds"])
inp_yaxis = bmo.widgets.Select(title="Y-Axis:",
                             value="pr",
                             options=["tasmin", "tasmax", "pr", "rsds"])

inp_xaxis.on_change('value', upd_axis)
inp_yaxis.on_change('value', upd_axis)

inp_country.on_change('value', upd_lat_lon)

# Handle on click_events (unfortunately show spinner with js due to lag otherwise)
inp_gen_upd.on_event(bo.events.ButtonClick, gen_upd_plot)
inp_gen_upd.js_on_event(
    bo.events.ButtonClick,
    bmo.CustomJS(args=dict(div_spinner=div_spinner, spinner_text=spinner_text),
                 code=show_spinner_js))

inputs = bo.layouts.row([
    bo.layouts.column([
        bo.layouts.row([inp_lat, inp_lon, inp_country]),
        bo.layouts.row([inp_time_mean, inp_exp]),
        bo.layouts.row([inp_gen_upd])
    ]),
    bo.layouts.column([
        bo.layouts.row([div_spinner]),
    ]),
])

l = bo.layouts.layout([
    bo.layouts.row([div_desc]),
    inputs,
Beispiel #14
0
def generate_plot(data, df_all_prediction):
    COLORS = d3["Category10"][10]

    tooltips = f"""
            <div>
                <p>
                    <span style="font-size: 12px; color: black;font-family:century gothic;">Nombre de cas : </span>
                    <span style="font-size: 12px; color: {COLORS[0]}; font-weight: bold;font-family:century gothic;">@total_cases</span>
                <br> 
                    <span style="font-size: 12px; color: black;font-family:century gothic;">Nombre de nouveaux cas : </span>
                    <span style="font-size: 12px; color: {COLORS[1]}; font-weight: bold;font-family:century gothic;">@new_cases</span>
                <br> 
                    <span style="font-size: 12px; color: black;font-family:century gothic;">Nombre de deces : </span>
                    <span style="font-size: 12px; color: {COLORS[3]}; font-weight: bold;font-family:century gothic;">@total_deaths</span>
                <br> 
                    <span style="font-size: 12px; color: black;font-family:century gothic;">Nombre nouveaux deces : </span>
                    <span style="font-size: 12px; color: {COLORS[5]}; font-weight: bold;font-family:century gothic;">@new_deaths</span>
                <br> 
                    <span style="font-size: 12px; color: black;font-family:century gothic;">Date : </span>
                    <span style="font-size: 12px; color: black; font-weight: bold;font-family:century gothic;">@date_str</span>
                </p>
            </div>
        """

    tooltips_predictions = (f"""
            <div>
                <p>
                    <span style="font-size: 12px; color: black;font-family:century gothic;">Prédiction nombre de cas : </span>
                    <span style="font-size: 12px; color: {COLORS[0]}; font-weight: bold;font-family:century gothic;">@median_display</span>
                <br> 
                    <span style="font-size: 12px; color: black;font-family:century gothic;">Date : </span>
                    <span style="font-size: 12px; color: black; font-weight: bold;font-family:century gothic;">"""
                            + """@date_str</span>
                </p>
            </div>
        """)

    hover = bkm.tools.HoverTool(names=["line_total"],
                                tooltips=tooltips,
                                mode="vline")

    hover_prediction = bkm.tools.HoverTool(
        names=["prediction"],
        tooltips=tooltips_predictions,
    )

    # --- define all DataSource needed --- #

    source_all = bkm.ColumnDataSource(data)
    country = "World"
    source = bkm.ColumnDataSource(get_country(data, country))

    source_all_prediction = bkm.ColumnDataSource(df_all_prediction)
    source_prediction = bkm.ColumnDataSource(
        get_country(df_all_prediction, country))

    date_end_training = np.unique(
        get_country(df_all_prediction, country)["date_end_train"])[-1]
    source_prediction_end_date = bkm.ColumnDataSource(
        get_country(df_all_prediction, country)[get_country(
            df_all_prediction, country).date_end_train == date_end_training])

    slider = bkm.Slider(
        start=0,
        end=len(
            np.unique(
                get_country(df_all_prediction, country)["date_end_train"])) -
        1,
        value=0,
        step=1,
        title="Days dropped for prediction",
    )

    # ----------- #

    p = bkp.figure(
        y_axis_type="linear",
        x_axis_type="datetime",
        sizing_mode="stretch_both",
        title=f"Covid 19 evolution: {country}",
        x_axis_label="date",
        y_axis_label="Total number of Covid 19 cases",
        tools=[hover, "pan", "wheel_zoom", "reset"],
        x_range=[
            get_country(data, country).date.min(),
            get_country(data, country).date.max() + datetime.timedelta(days=1),
        ],
        y_range=[
            -get_country(data, country).total_cases.max() * 0.05,
            get_country(data, country).total_cases.max() * 1.1,
        ],
    )
    p.yaxis.formatter = bkm.formatters.NumeralTickFormatter(format="0,0")
    p.xaxis.formatter = bkm.formatters.DatetimeTickFormatter(
        days=["%d/%m", "%d%a"], months=["%m/%Y", "%b %Y"])
    p.add_tools(hover_prediction)
    p.toolbar.active_drag = None

    # p.toolbar.active_scroll = p.select_one(bkm.WheelZoomTool)

    y_extra_range_max = np.max([
        np.max(get_country(data, country).new_cases.values),
        np.max(get_country(data, country).total_deaths.values),
    ])

    p.extra_y_ranges = {
        "Number of deaths":
        bkm.Range1d(start=-0.05 * y_extra_range_max,
                    end=1.1 * y_extra_range_max)
    }
    p.add_layout(
        bkm.LinearAxis(
            y_range_name="Number of deaths",
            axis_label="New Covid 19 cases",
            formatter=bkm.formatters.NumeralTickFormatter(format="0,0"),
        ),
        "right",
    )

    # --- plot total cases --- #

    p.line(
        source=source,
        x="date",
        y="total_cases",
        name="line_total",
        color=COLORS[0],
        legend_label="total cases",
        muted_alpha=0.1,
    )
    p.circle(source=source,
             x="date",
             y="total_cases",
             color=COLORS[0],
             muted_alpha=0.1)

    # --- plot new cases --- #

    p.vbar(
        source=source,
        x="date",
        top="new_cases",
        color=COLORS[1],
        width=50e6,
        alpha=0.5,
        name="bar",
        y_range_name="Number of deaths",
        legend_label="new cases",
        muted_alpha=0.1,
    )

    # --- plot total death --- #

    p.line(
        source=source,
        x="date",
        y="total_deaths",
        color=COLORS[3],
        y_range_name="Number of deaths",
        name="line_death",
        legend_label="total deaths",
        muted_alpha=0.1,
    )
    p.circle(
        source=source,
        x="date",
        y="total_deaths",
        color=COLORS[3],
        y_range_name="Number of deaths",
        muted_alpha=0.1,
    )

    # --- plot new death --- #

    p.vbar(
        source=source,
        x="date",
        top="new_deaths",
        color=COLORS[5],
        width=50e6,
        alpha=0.5,
        y_range_name="Number of deaths",
        legend_label="new deaths",
        muted_alpha=0.1,
    )

    button_click_count = bkm.ColumnDataSource({"clicks": [0]})

    select = bkm.Select(title="Country: ",
                        value=country,
                        options=list(data.location.unique()))
    button_log = bkm.Button(label="Log Scale", button_type="primary")

    # --- Predictions --- #

    median_prediction = p.line(
        source=source_prediction_end_date,
        x="date",
        y="median",
        line_color=COLORS[0],
        name="prediction",
    )
    prediction_cases_line = p.line(
        source=source_prediction_end_date,
        x="date",
        y="derivative",
        color=COLORS[1],
        y_range_name="Number of deaths",
    )

    band_low = bkm.Band(
        source=source_prediction_end_date,
        base="date",
        lower="25%",
        upper="median",
        fill_color=COLORS[0],
        level="underlay",
        fill_alpha=0.1,
        line_width=0.5,
        line_color="black",
    )

    band_high = bkm.Band(
        source=source_prediction_end_date,
        base="date",
        lower="median",
        upper="75%",
        fill_color=COLORS[0],
        level="underlay",
        fill_alpha=0.1,
        line_width=0.5,
        line_color="black",
    )

    median_prediction.visible = False
    prediction_cases_line.visible = False
    band_low.visible = False
    band_high.visible = False

    p.add_layout(band_low)
    p.add_layout(band_high)

    button_prediction = bkm.Button(label="Show predictions",
                                   button_type="primary")

    # -- Callback -- #

    callback = bkm.CustomJS(
        args=dict(
            source=source,
            source_all=source_all,
            select=select,
            x_range=p.x_range,
            y_range_left=p.y_range,
            y_range_right=p.extra_y_ranges["Number of deaths"],
            title=p.title,
            button_click_count=button_click_count,
            slider=slider,
            source_all_prediction=source_all_prediction,
            source_prediction=source_prediction,
            source_prediction_end_date=source_prediction_end_date,
            median_prediction=median_prediction,
            band_low=band_low,
            prediction_cases_line=prediction_cases_line,
            band_high=band_high,
        ),
        code="""
        var country = select.value
    
        var date = source_all.data['date']
        var date_str = source_all.data['date_str']
        var location = source_all.data['location']
        var total_cases = source_all.data['total_cases']
        var new_cases = source_all.data['new_cases']
        var total_deaths = source_all.data['total_deaths']
        var new_deaths = source_all.data['new_deaths']
    
    
        var new_date = []
        var new_date_str = []
        var new_total_cases = []
        var new_new_cases = []
        var new_total_deaths = []
        var new_new_deaths = []
    
    
        for(var i=0; i < date.length; i++){
            if(location[i]==country){
                new_date.push(date[i]);
                new_date_str.push(date_str[i])
                new_total_cases.push(total_cases[i]);
                new_new_cases.push(new_cases[i]);
                new_total_deaths.push(total_deaths[i]);
                new_new_deaths.push(new_deaths[i]);
            }
        }
    
        source.data['date']=new_date;
        source.data['date_str']=new_date_str;
        source.data['total_cases']=new_total_cases;
        source.data['new_cases']=new_new_cases;
        source.data['total_deaths']=new_total_deaths;
        source.data['new_deaths']=new_new_deaths;
    
        const new_cases_no_Nan = new_new_cases.filter(function (value) {
            return !Number.isNaN(value);
        });
        const cases_no_Nan = new_total_cases.filter(function (value) {
            return !Number.isNaN(value);
        });
    
        y_range_right.setv({"start": -0.05*Math.max.apply(Math, new_cases_no_Nan.concat(new_total_deaths)), 
                            "end": 1.1*Math.max.apply(Math, new_cases_no_Nan.concat(new_total_deaths))})
    
        y_range_left.setv({"start": -0.05*Math.max.apply(Math, cases_no_Nan), 
                           "end": 1.1*Math.max.apply(Math, cases_no_Nan)})
    
        x_range.setv({"start": Math.min.apply(Math, new_date), "end": 1.0001*Math.max.apply(Math, new_date)})
    
        title.text = "Evolution du nombre de cas en " + country
    
        source.change.emit();
    
    
        // change value of predictions
    
        button_click_count.data.clicks = 0
    
        median_prediction.visible = false
        band_low.visible = false
        band_high.visible = false
        prediction_cases_line.visble = false
    
        var date_end_prediction = source_all_prediction.data['date_end_train']
    
        var location = source_all_prediction.data['location']
        var date = source_all_prediction.data['date']
        var date_str = source_all_prediction.data['date_str']
        var quantile_1 = source_all_prediction.data['25%']
        var quantile_2 = source_all_prediction.data['median']
        var quantile_3 = source_all_prediction.data['75%']
        var new_cases = source_all_prediction.data['derivative']
        var median_prediction = source_all_prediction.data['median_display']
    
        var new_date = []
        var new_date_str = []
        var new_date_end_prediction = []
        var new_quantile_1 = []
        var new_quantile_2 = []
        var new_quantile_3 = []
        var new_new_cases = []
        var new_median_prediction = []
    
        for(var i=0; i < quantile_1.length; i++){
            if(location[i]==country){
                new_date.push(date[i])
                new_date_str.push(date_str[i])
                new_date_end_prediction.push(date_end_prediction[i])
                new_quantile_1.push(quantile_1[i]);
                new_quantile_2.push(quantile_2[i]);
                new_quantile_3.push(quantile_3[i]);
                new_new_cases.push(new_cases[i]);
                new_median_prediction.push(median_prediction[i]);
            }
        }   
        source_prediction.data['date']=new_date
        source_prediction.data['date_str']=new_date_str
        source_prediction.data['date_end_train']=new_date_end_prediction
        source_prediction.data['25%']=new_quantile_1;
        source_prediction.data['median']=new_quantile_2;
        source_prediction.data['75%']=new_quantile_3;
        source_prediction.data['derivative']=new_new_cases;
        source_prediction.data['median_display']=new_median_prediction;
    
    
        var n = new_date.length
        var max_date = Math.max.apply(Math, new_date_end_prediction)
    
        var new_date_bis = []
        var new_date_str_bis = []
        var new_date_end_prediction_bis = []
        var new_quantile_1_bis = []
        var new_quantile_2_bis = []
        var new_quantile_3_bis = []
        var new_new_cases_bis = []
        var new_median_prediction_bis = []
    
        for(var i=0; i < n; i++){
            if(new_date_end_prediction[i]==max_date){
                new_date_bis.push(new_date[i])
                new_date_str_bis.push(new_date_str[i])
                new_date_end_prediction_bis.push(new_date_end_prediction[i])
                new_quantile_1_bis.push(new_quantile_1[i]);
                new_quantile_2_bis.push(new_quantile_2[i]);
                new_quantile_3_bis.push(new_quantile_3[i]);
                new_new_cases_bis.push(new_new_cases[i]);
                new_median_prediction_bis.push(new_median_prediction[i]);
            }
        }
    
        var n = new_date_bis.length
        var max_date = Math.max.apply(Math, new_date_end_prediction_bis)
    
        source_prediction_end_date.data['date']=new_date_bis
        source_prediction_end_date.data['date_str']=new_date_str_bis
        source_prediction_end_date.data['date_end_train']=new_date_end_prediction_bis
        source_prediction_end_date.data['25%']=new_quantile_1_bis;
        source_prediction_end_date.data['median']=new_quantile_2_bis;
        source_prediction_end_date.data['75%']=new_quantile_3_bis;
        source_prediction_end_date.data['derivative']=new_new_cases_bis;
        source_prediction_end_date.data['median_display']=new_median_prediction_bis;
    
        source_prediction.change.emit();
        source_prediction_end_date.change.emit()
    
    
    
        const unique = (value, index, self) => {
                   return self.indexOf(value) === index
               }
    
        // change slider value
    
        slider.setv({"end": new_date_end_prediction.filter(unique).length - 1, "value": 0})
    
        """,
    )

    callback_button = bkm.CustomJS(
        args=dict(y_axis=p.left, title=p.title),
        code="""
        console.log(y_axis)
        y_axis = LogAxis()
    """,
    )

    select.js_on_change("value", callback)
    button_log.js_on_click(callback_button)

    callback_button = bkm.CustomJS(
        args=dict(
            source=source,
            source_prediction=source_prediction,
            source_all_prediction=source_all_prediction,
            source_prediction_end_date=source_prediction_end_date,
            select=select,
            button_prediction=button_prediction,
            median_prediction=median_prediction,
            band_low=band_low,
            prediction_cases_line=prediction_cases_line,
            band_high=band_high,
            button_click_count=button_click_count,
            x_range=p.x_range,
            y_range_left=p.y_range,
            y_range_right=p.extra_y_ranges["Number of deaths"],
        ),
        code="""
           // function to get unique value of an array
           const unique = (value, index, self) => {
               return self.indexOf(value) === index
           }

           var date = source.data['date'];
           var total_cases = source.data['total_cases'];
           var new_cases = source.data['new_cases'];
           var total_deaths = source.data['total_deaths'];

           var date_prediction = source_prediction.data['date'];
           var total_cases_prediction = source_prediction.data['75%'];

           const new_cases_no_Nan = new_cases.filter(function (value) {
               return !Number.isNaN(value);
           });
           const cases_no_Nan = total_cases.filter(function (value) {
               return !Number.isNaN(value);
           });

           var country = select.value
           button_click_count.data.clicks ++
           var show_prediction = (button_click_count.data.clicks % 2) == 1

           var locations_predicted = source_all_prediction.data['location'].filter(unique)

           if (locations_predicted.includes(country) == false){
               window.alert("This country doesn't have prediction: Available countries are: " + locations_predicted);
           }
           else{
               if (show_prediction == true){
                   median_prediction.visible = true
                   band_low.visible = true
                   band_high.visible = true
                   prediction_cases_line.visble = true
                   const y_range_right_values = [].concat([].slice.call(new_cases_no_Nan), [].slice.call(total_deaths))

                   y_range_left.setv({"start": -0.05*Math.max.apply(Math, total_cases_prediction), "end": 1.1 * Math.max.apply(Math, total_cases_prediction)})
                   y_range_right.setv({"start": -0.05*Math.max.apply(Math, y_range_right_values) * Math.max.apply(Math, total_cases_prediction) / Math.max.apply(Math, cases_no_Nan),
                                       "end": 1.1*Math.max.apply(Math, y_range_right_values) * Math.max.apply(Math, total_cases_prediction) / Math.max.apply(Math, cases_no_Nan)})

                   x_range.setv({"start": Math.min.apply(Math, date_prediction), "end": 1.0001*Math.max.apply(Math, date_prediction)})
               }
               else{
                   median_prediction.visible = false
                   band_low.visible = false
                   band_high.visible = false
                   prediction_cases_line.visble = false
                   const y_range_right_values = [].concat([].slice.call(new_cases_no_Nan), [].slice.call(total_deaths))

                   y_range_left.setv({"start": -0.05*Math.max.apply(Math, cases_no_Nan), "end": 1.1*Math.max.apply(Math, cases_no_Nan)})
                   y_range_right.setv({"start": -0.05*Math.max.apply(Math, y_range_right_values), "end": 1.1*Math.max.apply(Math, y_range_right_values)})
                   x_range.setv({"start": Math.min.apply(Math, date), "end": 1.0001*Math.max.apply(Math, date)})

               }
           }


           """,
    )

    button_prediction.js_on_click(callback_button)

    callback_slider = bkm.CustomJS(
        args=dict(
            source=source,
            source_prediction=source_prediction,
            source_all_prediction=source_all_prediction,
            source_prediction_end_date=source_prediction_end_date,
            select=select,
            prediction_cases_line=prediction_cases_line,
            slider=slider,
            button_click_count=button_click_count,
            x_range=p.x_range,
            y_range_left=p.y_range,
            y_range_right=p.extra_y_ranges["Number of deaths"],
        ),
        code="""

                           // function to get unique value of an array
                           const unique = (value, index, self) => {
                               return self.indexOf(value) === index
                           }

                           var slider_value = slider.value
                           var country = select.value

                           var date_prediction = source_prediction.data['date']
                           var date_str = source_prediction.data['date_str']
                           var date_end_prediction = source_prediction.data['date_end_train']
                           var quantile_1 = source_prediction.data['25%'];
                           var quantile_2 = source_prediction.data['median']
                           var quantile_3 = source_prediction.data['75%']
                           var new_cases = source_prediction.data['derivative'];
                           var median_prediction = source_prediction.data['median_display']

                           var unique_end_prediction = date_end_prediction.filter(unique)

                           var show_prediction = (button_click_count.data.clicks % 2) == 1
                           var locations_predicted = source_all_prediction.data['location'].filter(unique)

                           if (show_prediction == true && locations_predicted.includes(country)){
                                var new_date_prediction = []
                                var new_date_str = []
                                var new_date_end_prediction = []
                                var new_quantile_1 = []
                                var new_quantile_2 = []
                                var new_quantile_3 = []
                                var new_new_cases = []
                                var new_median_prediction = []

                                for(var i=0; i < quantile_1.length; i++){
                                    if(date_end_prediction[i]==unique_end_prediction[slider.end - slider_value]){
                                        new_date_prediction.push(date_prediction[i])
                                        new_date_str.push(date_str[i])
                                        new_date_end_prediction.push(date_end_prediction[i])
                                        new_quantile_1.push(quantile_1[i]);
                                        new_quantile_2.push(quantile_2[i]);
                                        new_quantile_3.push(quantile_3[i]);
                                        new_new_cases.push(new_cases[i]);
                                        new_median_prediction.push(median_prediction[i]);
                                    }
                                }   


                                source_prediction_end_date.data['date']=new_date_prediction
                                source_prediction_end_date.data['date_str']=new_date_str
                                source_prediction_end_date.data['date_end_train']=new_date_end_prediction
                                source_prediction_end_date.data['25%']=new_quantile_1;
                                source_prediction_end_date.data['median']=new_quantile_2;
                                source_prediction_end_date.data['75%']=new_quantile_3;
                                source_prediction_end_date.data['derivative']=new_new_cases;
                                source_prediction_end_date.data['median_display']=new_median_prediction;

                                source_prediction_end_date.change.emit();

                                var date_prediction = source_prediction_end_date.data['date'];
                                var total_cases_prediction = source_prediction_end_date.data['75%'];

                                const new_cases_no_Nan = new_cases.filter(function (value) {
                                    return !Number.isNaN(value);
                                 });
                                const cases_no_Nan = quantile_2.filter(function (value) {
                                   return !Number.isNaN(value);
                                 });


                                // y_range_left.setv({"start": -0.05*Math.max.apply(Math, total_cases_prediction), "end": 1.1*Math.max.apply(Math, total_cases_prediction)})
                                // x_range.setv({"start": Math.min.apply(Math, date_prediction), "end": 1.0001*Math.max.apply(Math, date_prediction)})

                           }

                                   """,
    )

    slider.js_on_change("value", callback_slider)

    p.legend.location = "top_left"
    p.legend.click_policy = "mute"

    return select, button_prediction, slider, p