Exemplo n.º 1
0
source.on_change('data', clear_message)

hover.callback = CustomJS(args=dict(cb=checkbox),
                          code="""
        if(!cb.active.includes(%d)) {
            document.getElementsByClassName('bk-tooltip')[%d].style.display = 'none';
        }
    """ % (1, 0))

checkbox.callback = CustomJS(args=dict(
    p0=circle,
    p1=line_regr,
    p2=circle_fit,
),
                             code="""
        //Toggle glyph visibility based on checkbox status
        p0.visible = cb_obj.active.includes(0);
        p1.visible = cb_obj.active.includes(1);
        p2.visible = cb_obj.active.includes(2);
    """)

click_reset_tool = CustomJS(args=dict(p=plot),
                            code="""
        p.toolbar.tools[""" + util.reset_tool_index(g.TOOLS3) +
                            """].trigger('do');
    """)

device_slc.on_change('value', device_slc_callback)
device_slc.js_on_change(
    'value',
Exemplo n.º 2
0
def templateAcceptedLoanPerRegion():
    LABELS = ["Central", "Mid - Atlantic", "NorthEast", "NorthWest", "South", "SouthEast", "SouthWest"]
    colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#17becf']
    data = pd.read_csv(DATA + 'perc_acc_loan_per_region_date_compact.csv')

    central = data['Central'] / 100
    midatl = data['Mid-Atlantic'] / 100
    northe = data['Northeast'] / 100
    northw = data['Northwest'] / 100
    south = data['South'] / 100
    southe = data['Southeast'] / 100
    southw = data['Southwest'] / 100
    date = data['date']

    source = ColumnDataSource(data=dict(x=[datetime.strptime(d, '%b-%Y') for d in date.values],
                                        Central=central,
                                        MidAtlantic=midatl,
                                        Northeast=northe,
                                        Northwest=northw,
                                        South=south,
                                        Southeast=southe,
                                        Southwest=southw
                                        ))

    props = dict(line_width=4, line_alpha=0.8)
    p = Figure(x_axis_type="datetime", width=1200, height=380)
    p0 = p.line('x', 'Central', source=source, legend="Central", line_color=colors[0], **props)
    p1 = p.line('x', 'MidAtlantic', source=source, legend="Mid - Atlantic", line_color=colors[1], **props)
    p2 = p.line('x', 'Northeast', source=source, legend="NorthEast", line_color=colors[2], **props)
    p3 = p.line('x', 'Northwest', source=source, legend="NorthWest", line_color=colors[3], **props)
    p4 = p.line('x', 'South', source=source, legend="South", line_color=colors[4], **props)
    p5 = p.line('x', 'Southeast', source=source, legend="SouthEast", line_color=colors[5], **props)
    p6 = p.line('x', 'Southwest', source=source, legend="SouthWest", line_color=colors[6], **props)

    p.yaxis.axis_label = 'Percentage of accepted loans'
    p.yaxis[0].formatter = NumeralTickFormatter(format="0.0%")
    p.border_fill_color = LIGHT_GREEN
    p.background_fill_color = LIGHT_GREEN
    p.legend.background_fill_color = LIGHT_GREEN
    p.legend.background_fill_alpha = 0.5

    checkbox = CheckboxGroup(
        labels=LABELS,
        inline=True,
        active=[0, 1, 2, 3, 4, 5, 6],
        width=800)

    code = """
        //console.log(cb_obj.active);
        p0.visible = false;
        p1.visible = false;
        p2.visible = false;
        p3.visible = false;
        p4.visible = false;
        p5.visible = false;
        p6.visible = false;

        for (i in checkbox.active) {
            //console.log(cb_obj.active[i]);
            if (checkbox.active[i] == 0) {
                p0.visible = true;
            } else if (checkbox.active[i] == 1) {
                p1.visible = true;
            } else if (checkbox.active[i] == 2) {
                p2.visible = true;
            } else if (checkbox.active[i] == 3) {
                p3.visible = true;
            } else if (checkbox.active[i] == 4) {
                p4.visible = true;
            } else if (checkbox.active[i] == 5) {
                p5.visible = true;
            } else if (checkbox.active[i] == 6) {
                p6.visible = true;
            }
        }
    """

    checkbox.callback = CustomJS(args=dict(p0=p0, p1=p1, p2=p2, p3=p3, p4=p4, p5=p5, p6=p6, checkbox=checkbox),
                                 code=code)

    boundaries = open(DATA + 'boundaries.json').read()
    states = json.loads(boundaries)
    region_state = pd.read_csv(DATA + 'region-state.csv', header=0)
    region_state = region_state.set_index('state')

    state_xs = [states[code]["lons"] for code in states]
    state_ys = [states[code]["lats"] for code in states]
    name = states.keys()

    colors_state = []

    for i in name:
        if i != 'AK' and i != 'HI':
            reg = region_state.loc[i]['region']
            if reg == "Central":
                colors_state.append(colors[0])
            elif reg == "Mid-Atlantic":
                colors_state.append(colors[1])
            elif reg == "Northeast":
                colors_state.append(colors[2])
            elif reg == "Northwest":
                colors_state.append(colors[3])
            elif reg == "South":
                colors_state.append(colors[4])
            elif reg == "Southeast":
                colors_state.append(colors[5])
            elif reg == "Southwest":
                colors_state.append(colors[6])

    source = ColumnDataSource(data=dict(
        x=state_xs,
        y=state_ys,
        name=name,
        colors=colors_state,
    ))

    q = figure(title="",
               toolbar_location=None,
               plot_width=300,
               plot_height=160
               )
    q.xaxis.visible = False
    q.yaxis.visible = False
    q.xgrid.grid_line_color = None
    q.ygrid.grid_line_color = None
    q.min_border_left = False
    q.min_border_right = False
    q.min_border_top = False
    q.min_border_bottom = False
    q.border_fill_color = LIGHT_GREEN
    q.background_fill_color = LIGHT_GREEN

    q.patches('x', 'y', source=source,
              fill_color='colors',
              fill_alpha=0.9, line_color="white", line_width=0.1)

    layout = VBox(q, checkbox, p)

    # show(layout)

    script, div = components(layout)

    return script, div
Exemplo n.º 3
0
checkbox1 = CheckboxGroup(labels=["", "", "", "", "", "", "", ""],
                          active=[0, 1, 2, 3, 4, 5, 6, 7, 8],
                          sizing_mode='scale_both',
                          width=200,
                          height=200)
checkbox1.height = 200
checkbox1.callback = CustomJS.from_coffeescript(args=dict(l0=l_mon,
                                                          l1=l_tue,
                                                          l2=l_wed,
                                                          l3=l_thu,
                                                          l4=l_fri,
                                                          l5=l_sat,
                                                          l6=l_sun,
                                                          l7=l_std,
                                                          checkbox=checkbox1),
                                                code="""
                                  l0.visible = 0 in checkbox.active;
                                  l1.visible = 1 in checkbox.active;
                                  l2.visible = 2 in checkbox.active;
                                  l3.visible = 3 in checkbox.active;
                                  l4.visible = 4 in checkbox.active;
                                  l5.visible = 5 in checkbox.active;
                                  l6.visible = 6 in checkbox.active;
                                  l7.visible = 7 in checkbox.active;
                                  """)

checkbox2 = CheckboxGroup(labels=["", "", ""], active=[0, 1, 2])
checkbox2.callback = CustomJS.from_coffeescript(args=dict(l0=l_14,
                                                          l1=l_15,
                                                          l2=l_16,
                                                          checkbox=checkbox2),
Exemplo n.º 4
0
def plot_density_onegame(df, name, feat_plot):

    bandwidth = 5
    range_start = -100
    range_end = 180
    r = len(df.groupby(name).count().index)
    l = list(df.groupby(name).count().index)
    l = sorted(l)

    def style(p):
        # Title
        p.title.align = 'center'
        p.title.text_font_size = '20pt'
        p.title.text_font = 'serif'

        # Axis titles
        p.xaxis.axis_label_text_font_size = '14pt'
        p.xaxis.axis_label_text_font_style = 'bold'
        p.yaxis.axis_label_text_font_size = '14pt'
        p.yaxis.axis_label_text_font_style = 'bold'

        # Tick labels
        p.xaxis.major_label_text_font_size = '12pt'
        p.yaxis.major_label_text_font_size = '12pt'

        return p

    x = np.linspace(range_start, range_end, 100)

    source_dict = dict(x=x)
    line_dict = dict()
    line_colors = Category20_16
    line_colors.sort()

    for i in range(0, r):
        tmp_df = df[df[name] == l[i]]
        tmp_kde = gaussian_kde(tmp_df[feat_plot], bw_method=bandwidth)
        tmp_y = tmp_kde.pdf(x)
        #y_number = "y%s" % i
        y_number = l[i]
        source_dict[y_number] = tmp_y

    source = ColumnDataSource(data=source_dict)
    p = figure(plot_width=600, plot_height=400)

    for i in range(0, r):
        #y_number = "y%s" % i
        y_number = l[i]
        line_number = "line%s" % i
        line = p.line('x',
                      y_number,
                      source=source,
                      line_width=3,
                      line_alpha=0.6,
                      line_color=line_colors[i])
        line_dict[line_number] = line

    hover = HoverTool(tooltips=[(feat_plot, '$x'), ('Density', '$y')],
                      line_policy='next')
    p.add_tools(hover)
    p = style(p)

    checkbox = CheckboxGroup(labels=l, active=list(range(r)))

    checkbox.callback = CustomJS(args=line_dict,
                                 code="""
        //console.log(cb_obj.active);
        line0.visible = false;
        line1.visible = false;
        line2.visible = false;
        line3.visible = false;
        line4.visible = false;
        line5.visible = false;
        line6.visible = false;
        line7.visible = false;
        line8.visible = false;
        line9.visible = false;
        line10.visible = false;
        line11.visible = false;
        for (i in cb_obj.active) {
            //console.log(cb_obj.active[i]);
            if (cb_obj.active[i] == 0) {
                line0.visible = true;
            } else if (cb_obj.active[i] == 1) {
                line1.visible = true;
            }
              else if (cb_obj.active[i] == 2) {
                line2.visible = true;
            }
              else if (cb_obj.active[i] == 3) {
                line3.visible = true;
            }
              else if (cb_obj.active[i] == 4) {
                line4.visible = true;
            }
              else if (cb_obj.active[i] == 5) {
                line5.visible = true;
            }
              else if (cb_obj.active[i] == 6) {
                line6.visible = true;
            }
              else if (cb_obj.active[i] == 7) {
                line7.visible = true;
            }
              else if (cb_obj.active[i] == 8) {
                line8.visible = true;
            }
              else if (cb_obj.active[i] == 9) {
                line9.visible = true;
            }
              else if (cb_obj.active[i] == 10) {
                line10.visible = true;
            }
              else if (cb_obj.active[i] == 11) {
                line11.visible = true;
            }
        }
    """)

    controls = WidgetBox(checkbox)
    layout = row(controls, p)

    tab = Panel(child=layout, title="Density Plot of " + feat_plot)

    return tab
Exemplo n.º 5
0
def make_timeline_html(input_dir_path: str, output_path: str) -> None:
    # Load Data
    path = Path(input_dir_path) / 'pep_graph.gpickle'
    pep_graph = nx.read_gpickle(path)

    path = Path(input_dir_path) / 'python_release_info.csv'
    release_df = pd.read_csv(path,
                             encoding='utf-8',
                             parse_dates=['release_date'])

    release_df = release_df[release_df.micro == 0]
    release_df['color'] = release_df.major.apply(lambda x: PYTHON_YELLOW_COLOR_CODE if x == 2 else PYTHON_BLUE_COLOR_CODE)  # 2, 3以外が出てきたら再考すること

    node_dict = dict(pep_graph.nodes(data=True))
    date_list = [value['Created_dt'] for key, value in node_dict.items()]

    min_date = datetime.datetime(min(date_list).year, 1, 1)
    py2_release_label_data_source = tl_compo.generate_release_label_source(release_df,
                                                                           major_version=2,
                                                                           pos_x=min_date)
    py3_release_label_data_source = tl_compo.generate_release_label_source(release_df,
                                                                           major_version=3,
                                                                           pos_x=min_date)

    py2_release_line_data_source = tl_compo.generate_release_line_data_source(release_df,
                                                                              major_version=2)
    py3_release_line_data_source = tl_compo.generate_release_line_data_source(release_df,
                                                                              major_version=3)

    release_source_dict = {'py2_release_label_source': py2_release_label_data_source,
                           'py3_release_label_source': py3_release_label_data_source,
                           'py2_release_line_source': py2_release_line_data_source,
                           'py3_release_line_source': py3_release_line_data_source
                           }

    all_pep_data_source = compo.generate_node_data_source(pep_graph)

    # DataTable用のデータソースを用意する
    linked_from_table_source = table_compo.generate_data_table_data_source(pep_graph)
    link_to_table_source = table_compo.generate_data_table_data_source(pep_graph)

    linked_from_data_table = table_compo.generate_data_table(linked_from_table_source)
    link_to_data_table = table_compo.generate_data_table(link_to_table_source)

    linked_from_table_title_div = Div(text='<strong>PEP N is linked from ...</strong>',
                                      style={'color': BASE_FONT_COLOR})
    link_to_table_title_div = Div(text='<strong>PEP N links to ...</strong>',
                                  style={'color': BASE_FONT_COLOR})

    # Timeline用のデータソースを用意する
    timeline_display_circle_source = tl_compo.generate_timeline_data_source(pep_graph)
    timeline_label_source = tl_compo.generate_timeline_label_data_source(pep_graph)
    desc_start_date, _ = tl_compo.get_timeline_plot_range(pep_graph)
    desc_start_date = desc_start_date + datetime.timedelta(days=30)
    timeline_desc_label_source = tl_compo.generate_timeline_desc_data_source(xs=[desc_start_date, desc_start_date],
                                                                             ys=[1.7, 0.1],
                                                                             font_size=15)

    # 入力ボックス用のデータソース生成
    error_message_div = Div(width=300, height=8, style={'color': 'red'}, text='')

    title_div = Div(width=700,
                    style={'font-size': 'large',
                           'line-height': '1.5',
                           'color': BASE_FONT_COLOR})
    title_div.text = """
    Let's enter the PEP number in the left text box.<br>
    Then you can see the following information.
    <li>Which PEPs do link that PEP?</li>
    <li>Which PEPs are linked from that PEP?</li>
    """

    checkbox_group = CheckboxGroup(labels=["Show Python 2 release dates",
                                           "Show Python 3 release dates"],
                                   active=[0, 1])

    def callback_input_pep_number(all_pep_data_source=all_pep_data_source,
                                  link_to_table_source=link_to_table_source,
                                  linked_from_table_source=linked_from_table_source,
                                  link_to_table_title_div=link_to_table_title_div,
                                  linked_from_table_title_div=linked_from_table_title_div,
                                  timeline_display_circle_source=timeline_display_circle_source,
                                  timeline_label_source=timeline_label_source,
                                  timeline_desc_source=timeline_desc_label_source,
                                  title_div=title_div,
                                  error_message_div=error_message_div) -> None:
        """
        テキストボックスに文字入力されたときに実行される関数。
        PyScriptを使ってJavaScriptに変換される。
        参考: https://bokeh.pydata.org/en/latest/docs/user_guide/interaction/callbacks.html#customjs-with-a-python-function
        * このパラメータの設定の仕方以外にもあるかもしれない

        :param all_pep_data_source:
        :param link_to_table_source:
        :param linked_from_table_source:
        :param link_to_table_title_div:
        :param linked_from_table_title_div:
        :param timeline_display_circle_source:
        :param timeline_label_source:
        :param timeline_desc_source:
        :param title_div:
        :param error_message_div:
        :param debug_div:
        :return:
        """

        inputed_text = cb_obj['value']

        # PyScriptで変換するときに自分の外側の関数の呼び方がわからないので、
        # 暫定で関数内関数で定義する。
        def create_header_text(pep_dict: dict) -> str:
            if not pep_dict:
                return 'Not Found.'

            # .formatを使うとJavaScript変換後に実行時エラーになるので、
            # +演算子で連結している
            description_text = "<span>Created: " \
                               + pep_dict['Created_str'] \
                               + "&nbsp;&nbsp;&nbsp;&nbsp;Type: " \
                               + pep_dict['Type'] \
                               + "<br>"

            link_text = "<a href='https://www.python.org/dev/peps/pep-" \
                        + pep_dict['index'] \
                        + "/' target='_blank'>PEP " \
                        + pep_dict['PEP'] \
                        + "</a>"
            title_text = "<span style='font-size : xx-large;'>" \
                         + link_text \
                         + "<br>" \
                         + pep_dict['Title'] \
                         + " (" + pep_dict['Status'] + ")" \
                         + "</span>"

            return description_text + title_text

        def search_index_by_pep_number(text: str) -> int:
            index = 0

            for pep_number in all_pep_data_source['data']['PEP']:
                if text == str(pep_number):
                    return index
                index += 1

            return -1  # Not Found

        def get_inputed_pep_dict(text: int) -> dict:
            selected_index = search_index_by_pep_number(text)
            if selected_index == -1:
                return {}
            pep_dict = {}

            for key, value in all_pep_data_source.data.items():
                pep_dict[key] = value[selected_index]

            return pep_dict

        def get_pep_info(list_index: int) -> dict:
            pep_dict = {}

            for key, value in all_pep_data_source['data'].items():
                pep_dict[key] = value[list_index]

            return pep_dict

        def get_neighbor_node_info(pep_dict: dict,
                                   neighbor_type: str) -> dict:
            neighbors = dict()
            for key, value in all_pep_data_source.data.items():
                neighbors[key] = []

            for pep_id in pep_dict[neighbor_type]:
                index = search_index_by_pep_number(int(pep_id))
                work_pep_dict = get_pep_info(index)
                for key in neighbors.keys():
                    neighbors[key].append(work_pep_dict[key])
            return neighbors

        def generate_timeline_source_dict(pep_dict: dict) -> dict:

            in_edge_nodes_dict = get_neighbor_node_info(pep_dict,
                                                        'in_edge_nodes')
            out_edge_nodes_dict = get_neighbor_node_info(pep_dict,
                                                         'out_edge_nodes')
            in_edge_nodes_dict['y'] = [1.5] * len(in_edge_nodes_dict['PEP'])
            out_edge_nodes_dict['y'] = [0.5] * len(out_edge_nodes_dict['PEP'])

            timeline_source_dict = in_edge_nodes_dict
            del timeline_source_dict['in_degree']
            del timeline_source_dict['in_edge_nodes']
            del timeline_source_dict['out_degree']
            del timeline_source_dict['out_edge_nodes']
            for key, value in timeline_source_dict.items():
                timeline_source_dict[key] += out_edge_nodes_dict[key]
                if key == 'y':
                    timeline_source_dict[key].append(1)
                else:
                    timeline_source_dict[key].append(pep_dict[key])

            return timeline_source_dict

        def update_data_table(pep_dict: dict) -> None:
            linked_from_table_title_div.text = '<strong>PEP ' \
                                               + pep_dict['PEP'] \
                                               + ' is linked from ...</strong>'
            link_to_table_title_div.text = '<strong>PEP ' \
                                           + pep_dict['PEP'] \
                                           + ' links to ...</strong>'

            in_edge_nodes_dict = get_neighbor_node_info(pep_dict,
                                                        'in_edge_nodes')
            linked_from_table_source.data = in_edge_nodes_dict
            linked_from_table_source.change.emit()

            out_edge_nodes_dict = get_neighbor_node_info(pep_dict,
                                                         'out_edge_nodes')
            link_to_table_source.data = out_edge_nodes_dict
            link_to_table_source.change.emit()

        def update_timeline(pep_dict: dict) -> None:
            timeline_circle_dict = generate_timeline_source_dict(pep_dict)
            timeline_display_circle_source.data = timeline_circle_dict
            timeline_display_circle_source.change.emit()

            timeline_label_dict = generate_timeline_source_dict(pep_dict)
            timeline_label_dict['displayed_text'] = timeline_label_dict['PEP']
            timeline_label_source.data = timeline_label_dict
            timeline_label_source.change.emit()

            texts = ['PEP ' + pep_dict['PEP'] + ' is linked from...',
                     'PEP ' + pep_dict['PEP'] + ' links to...', ]

            timeline_desc_dict = dict(x=timeline_desc_source.data['x'],
                                      y=timeline_desc_source.data['y'],
                                      text=texts,
                                      size=timeline_desc_source.data['size'],
                                      )

            timeline_desc_source.data = timeline_desc_dict
            timeline_desc_source.change.emit()

        # 正規表現でタグを除去したいけど、JS変換後にreを呼べないので、暫定で<と>を外す
        inputed_text = inputed_text.replace('<', '')
        inputed_text = inputed_text.replace('>', '')
        inputed_text = inputed_text.strip()

        # 入力文字のチェック
        if not inputed_text:
            error_message_div.text = 'Please enter the number of PEP' + inputed_text
            return

        inputed_text = inputed_text.lstrip('0')

        # 表示の更新
        selected_pep_dict = get_inputed_pep_dict(inputed_text)

        if selected_pep_dict:
            title_div.text = create_header_text(selected_pep_dict)
            update_data_table(selected_pep_dict)
            update_timeline(selected_pep_dict)
            error_message_div.text = ""
        else:
            error_message_div.text = "Not Found: PEP " + inputed_text

    def callback_change_checkbox(py2_label_source=py2_release_label_data_source,
                                 py2_line_source=py2_release_line_data_source,
                                 py3_label_source=py3_release_label_data_source,
                                 py3_line_source=py3_release_line_data_source):

        def switch_show_or_hide(label_source, line_source, major_version):

            label_data = label_source.data
            line_data = line_source.data

            check_box_index_map = {2: 0, 3: 1}

            if check_box_index_map[major_version] in cb_obj.active:
                label_data['alpha'] = [1] * len(label_data['alpha'])
                line_data['alpha'] = [1] * len(line_data['alpha'])
            else:
                label_data['alpha'] = [0] * len(label_data['alpha'])
                line_data['alpha'] = [0] * len(line_data['alpha'])

            label_source.data = label_data
            label_source.change.emit()

            line_source.data = line_data
            line_source.change.emit()

        switch_show_or_hide(py2_label_source, py2_line_source, 2)
        switch_show_or_hide(py3_label_source, py3_line_source, 3)

    # Header Component
    pep_textinput = TextInput(title='PEP:',
                              placeholder='Please enter the PEP number.',
                              callback=CustomJS.from_py_func(callback_input_pep_number),
                              width=190)
    info_div = Div(width=200, height=20,
                   style={'background-color': '#175A89',
                          'padding': '5px',
                          'color': '#FFFFFF'})
    info_div.text = "<li>" \
                    "<a href='https://github.com/komo-fr/pep_map_site'><font color='#FFFFFF'>repository</font></a>" \
                    "</li>"
    inputbox_component = column(pep_textinput, error_message_div)
    color_desc_component = compo.generate_color_description_component()
    header_component = row(column(inputbox_component, color_desc_component),
                           title_div,
                           info_div)

    # Timeline Component
    checkbox_group.callback = CustomJS.from_py_func(callback_change_checkbox)
    timeline_plot = tl_compo.generate_timeline_plot(pep_graph,
                                                    timeline_display_circle_source,
                                                    timeline_label_source,
                                                    timeline_desc_label_source,
                                                    release_source_dict)
    as_of_date_div = Div(width=200, height=8, style={'color': 'red'})
    # TODO: fetch_start_datetimeを持っていないときの対応について決める
    fetch_datetime = pep_graph.graph['fetch_start_datetime'].strftime('%Y/%m/%d') \
        if 'fetch_start_datetime' in pep_graph.graph else 'Unknown'

    as_of_date_div.text = '* Data as of {}'.format(fetch_datetime)  # データ取得日
    timeline_component = column(timeline_plot, as_of_date_div)

    # Table Component
    margin_div = Div(width=50)
    link_to_table_component = column(link_to_table_title_div, link_to_data_table)
    linked_from_table_component = column(linked_from_table_title_div, linked_from_data_table)
    table_component = row(linked_from_table_component, margin_div, link_to_table_component)

    # TODO: ここでshowしなくても出力できる方法はないか?
    output_file(output_path, 'PEP Map | Timeline')

    show(column(header_component, checkbox_group, timeline_component, table_component))
Exemplo n.º 6
0
def basic_TS_plot(fullDataset):
    # Init values
    ticker = ""
    yLabel = ""
    descLine = ""
    plotX = []
    plotXLabel = []
    plotY = []
    legendList = []

    # BollingerBands
    all_top_bollingers = []
    all_bot_bollingers = []
    all_mid_bollingers = []
    all_bollinger_dates = []

    # Quartiles
    firstQuartiles = []
    medians = []
    thirdQuartiles = []

    # SETUP DATA
    for element in fullDataset:

        try:
            elementX = []
            elementXLabel = []
            elementY = []

            # Extract x and y's from the pairs provided in each element of the dataset
            if element["dataset"]["data"]:
                for e in range(0, len(element["dataset"]["data"])):
                    elementX.append(
                        datetime.strptime(element["dataset"]["data"][e][0],
                                          '%Y-%m-%d').date())
                    elementXLabel.append(str(element["dataset"]["data"][e][0]))
                    elementY.append(element["dataset"]["data"][e][1])

            databaseCode = "[" + element["dataset"]["database_code"] + "] "
            name = element["dataset"]["name"]

            if len(elementX) > 0:
                # Reverse the incoming data if it starts with the closest-to-present data. We want it list to start with the oldest data
                if len(elementX) > 1:
                    if elementX[0] > elementX[1]:
                        elementX.reverse()
                        elementY.reverse()
                plotX.append(elementX)
                plotXLabel.append(elementXLabel)
                plotY.append(elementY)

                # Bollinger Band Info prepare
                date_b, top_b, bot_b, mid_b = bollinger_bands(
                    2, elementX, elementY, 20)
                all_top_bollingers.append(top_b)
                all_mid_bollingers.append(mid_b)
                all_bot_bollingers.append(bot_b)
                # all_bollinger_dates.append(date_b)
                all_bollinger_dates.append(elementX)

            if element["dataset"]["data"]:
                if len(name) > 15:
                    legendList.append("Show/Hide: " + name[:30] + "...")
                else:
                    legendList.append(name)

            if element["dataset"]["data"]:
                # Prepare Quartiles
                numpyY = np.array(elementY)
                first_q = np.percentile(numpyY, 25)
                medi = np.percentile(numpyY, 50)
                third_q = np.percentile(numpyY, 75)

                firstQuartiles.append(first_q)
                medians.append(medi)
                thirdQuartiles.append(third_q)
        except Exception as e:
            logger.debug("ERROR: element in fullDataset could not be added")
            logger.debug(element)
            logger.debug(e)

    all_quartiles = [[]] * len(plotX)
    quartiles_names = [["First Quartile", "Median", "Third Quartile"]
                       ] * len(plotX)

    for i in range(len(plotX)):
        all_quartiles[i] = [firstQuartiles[i], medians[i], thirdQuartiles[i]]

    # If only one item is available from the fullDataset, the report can be tailored to that time-series only
    if len(fullDataset) == 1:

        titleLong = fullDataset[0]["dataset"]["name"]

        if len(titleLong) > 20:
            titleShort = titleLong[:10] + "..."
        else:
            titleShort = titleLong

        descLong = "Long description placeholder."
        descLine = '<abbr title="' + descLong + '">' + ticker + '</abbr>'
        yLabel = fullDataset[0]["dataset"]["column_names"][1]

    # generic title for multiple data sets
    else:
        titleShort = "Time-series for: " + fullDataset[0]["dataset"][
            "start_date"] + " to " + fullDataset[0]["dataset"]["end_date"]
        descLine = ticker
        yLabel = "Value(s)"  # The table below will be used to show the units. Ideally it should also figure in the legend

    # Prepare column data sources for the graphs. This is also where hover tool and other widgets get their information
    source = []

    # 'color' is created specifically for lasso tool - for the invisible, but selectable circle glyphs
    for i in range(len(plotX)):
        color = ["navy"] * len(plotX[i])
        source.append(
            ColumnDataSource(data=dict(x=plotX[i],
                                       y=plotY[i],
                                       color=color,
                                       topx=all_bollinger_dates[i],
                                       topy=all_top_bollingers[i],
                                       midx=all_bollinger_dates[i],
                                       midy=all_mid_bollingers[i],
                                       botx=all_bollinger_dates[i],
                                       boty=all_bot_bollingers[i])))

    PLOT_OPTIONS = dict(plot_width=400, plot_height=170)

    crosshair = CrosshairTool(dimensions="height")

    TOOLS = ['pan,wheel_zoom,box_zoom,reset,save,lasso_select'] + [crosshair]

    plot = figure(title=titleShort,
                  x_axis_type="datetime",
                  tools=TOOLS,
                  toolbar_location="above",
                  sizing_mode='scale_width',
                  **PLOT_OPTIONS)

    plot.xaxis.formatter = DatetimeTickFormatter(
        hours=["%d %B %Y"],
        days=["%d %B %Y"],
        months=["%d %B %Y"],
        years=["%d %B %Y"],
    )

    plot.xaxis.axis_label = 'Date(s)'
    plot.yaxis.axis_label = yLabel

    # Magma color palette is: black - purple - orange - tan - light tan
    # Viridis is a color paledtte: dark blue - greenblue - green - yellow
    # More palettes @
    # http://bokeh.pydata.org/en/latest/docs/reference/palettes.html
    colors_list = Viridis256
    shuffle(colors_list)

    # visible lines on graph creation
    plot_line_list = []

    bollinger_band_list = []

    for i in range(len(plotX)):
        # circles created for lasso average finding tool
        plot.circle("x", "y", color='color', size=1, source=source[i], alpha=0)
        # visible graph:
        plot_line_list.append(
            plot.line("x",
                      "y",
                      color=colors_list[i],
                      line_width=4,
                      name='standard',
                      source=source[i]))
        shuffle(colors_list)
        bollinger_band_list.append(
            plot.line("topx",
                      "topy",
                      color=colors_list[i],
                      line_width=1,
                      name='top',
                      source=source[i]))
        bollinger_band_list.append(
            plot.line("midx",
                      "midy",
                      color=colors_list[i],
                      line_width=1,
                      line_dash="dashed",
                      name='mid',
                      source=source[i]))
        bollinger_band_list.append(
            plot.line("botx",
                      "boty",
                      color=colors_list[i],
                      line_width=1,
                      name='bot',
                      source=source[i]))

    # Bollinger bands are initially off
    for i in range(len(bollinger_band_list)):
        bollinger_band_list[i].visible = True

    # A hover tool for each line (standard, top, mid, lower)
    hover = HoverTool(
        names=['standard'],
        tooltips=[
            ("Value", "@y{0,0.0000}"),  # FRED REMOVED comma HERE
            ("Date", "@x{%F}")
        ],
        formatters={"x": "datetime"},
        mode='vline')

    hover2 = HoverTool(names=['top'],
                       tooltips=[("Upper Band", "@topy{0,0.0000}"),
                                 ("Date", "@x{%F}")],
                       formatters={"x": "datetime"},
                       mode='vline')
    hover3 = HoverTool(names=['mid'],
                       tooltips=[("SMA", "@midy{0,0.0000}"),
                                 ("Date", "@x{%F}")],
                       formatters={"x": "datetime"},
                       mode='vline')
    hover4 = HoverTool(names=['bot'],
                       tooltips=[("Lower Band", "@boty{0,0.0000}"),
                                 ("Date", "@x{%F}")],
                       formatters={"x": "datetime"},
                       mode='vline')

    plot.add_tools(hover, hover2, hover3, hover4)

    # Set-up the multi-line representation (not using bokeh's multi-line) and the checkboxes
    list_active = []
    dictArgs = {}

    button_titles = []
    for i in range(0, len(plotX)):
        button_titles.append("Graph " + str(i + 1) + ": " + legendList[i])

    # Generate the JS code for checkbox group - show/hide graphs
    dynamicJS = '//console.log(cb_obj.active);'

    for line in range(0, len(plot_line_list)):
        dynamicJS += '\nline' + str(line * 4) + '.visible = false; '
        for i in range(3):
            dynamicJS += '\nline' + str(line * 4 + i +
                                        1) + '.visible = false; '

    dynamicJS += """
    for (i in cb_obj.active)
    {
    //console.log(cb_obj.active[i]);
    if (cb_obj.active[i] == 0)
    {
        line0.visible = true;
        if (bollToggle.active == true)\n"""
    dynamicJS += "{\n"
    for i in range(3):
        dynamicJS += 'line' + str(i + 1) + '.visible = true;\n'
    dynamicJS += '}}'

    for line in range(1, len(plot_line_list)):
        dynamicJS += '\nelse if (cb_obj.active[i] == ' + str(line) + ') {\n'
        dynamicJS += 'line' + str(line * 4) + '.visible = true;\n'
        dynamicJS += 'if (bollToggle.active == true) {\n'
        for i in range(3):
            dynamicJS += 'line' + str(line * 4 + i + 1) + '.visible = true;\n'
        dynamicJS += '\n}}'
    dynamicJS += '\nelse if (cb_obj.active[i] == ' + str(
        len(plot_line_list)) + ') {\n'
    for t in range(0, len(plot_line_list)):
        dynamicJS += 'if (bollToggle.active == true) {\n'
        for i in range(3):
            dynamicJS += 'line' + str(t * 4 + i + 1) + '.visible = true;\n'
        dynamicJS += '}\n'
    dynamicJS += '\n}'
    dynamicJS += '\n}'

    logger.debug("DEBUG: DynamicJS")
    logger.debug(dynamicJS)

    # list_active means the buttons initially ON at page load
    for line in range(0, len(plot_line_list)):
        list_active.append(line)
        key = "line" + str(line * 4)
        dictArgs.update({key: plot_line_list[line]})
        for i in range(3):
            key = "line" + str(line * 4 + i + 1)
            dictArgs.update({key: bollinger_band_list[line * 3 + i]})

    bollButton = Toggle(label='Bollinger On/Off', button_type='success')

    key = "bollToggle"
    dictArgs.update({key: bollButton})

    checkboxColor = ''
    if len(plotY) > 9:
        checkboxColor += '#E4E4E4;'
    else:
        checkboxColor += 'white;'

    checkbox = CheckboxGroup(labels=button_titles,
                             active=list_active,
                             width=450,
                             height=210)

    checkbox.callback = CustomJS(args=dictArgs, code=dynamicJS)
    # checkbox is 210 pixels high(max), with a vertical scrollbar and grey background color
    checkbox.css_classes = ["checkbox-scrollbar"]

    key = "checkbox"
    dictArgs.update({key: checkbox})

    selectAllJS = ''
    selectAllJS += "checkbox.active = ["
    for i in range(len(plotY)):
        if i != len(plotY) - 1:
            selectAllJS += str(i) + ', '
        else:
            selectAllJS += str(i)

    selectAllJS += "];\n"

    for i in range(len(plotY)):
        selectAllJS += 'line' + str(i * 4) + '.visible = true;\n'

    selectAllJS += 'if (bollToggle.active == true) {\n'

    for i in range(len(plotY)):
        for t in range(3):
            selectAllJS += 'line' + str(i * 4 + t + 1) + '.visible = true;\n'

    selectAllJS += '}'

    selectAllCallback = CustomJS(args=dictArgs, code=selectAllJS)
    selectAllButton = Button(label='Select All',
                             button_type='warning',
                             callback=selectAllCallback)

    deselectAllJS = "checkbox.active = [];\n"

    for i in range(len(plotY) * 4):
        deselectAllJS += 'line' + str(i) + '.visible = false;\n'

    deselectAllCallback = CustomJS(args=dictArgs, code=deselectAllJS)
    deselectAllButton = Button(label='Deselect All',
                               button_type='warning',
                               callback=deselectAllCallback)

    plotScript, plotDiv = components(plot)

    # printPlotJS = """
    #         var div = plot;
    #         console.log(plot);
    #         var data=divID.innerHTML;
    #         var myWindow = window.open('', 'my div', 'height=400,width=600');
    #         myWindow.document.write(div);
    #         myWindow.document.close(); // necessary for IE >= 10
    #
    #         myWindow.onload=function(){ // necessary if the div contain images
    #
    #             myWindow.focus(); // necessary for IE >= 10
    #             myWindow.print();
    #             myWindow.close();
    #         };
    # """

    # logger.debug("DEBUG: DynamicJS")
    # logger.debug(dynamicJS)

    sliderJS = """
        var window = cb_obj.value
        var sources = ["""

    for i in range(len(source)):
        if i != len(source) - 1:
            sliderJS += 'source' + str(i) + ', '
        else:
            sliderJS += 'source' + str(i)

    sliderJS += '];'

    sliderJS += """

        for (var i = 0, len=sources.length; i < len; i++) {
            var data = sources[i].data;
            var y = data['y']
            topy = data['topy']
            midy = data['midy']
            boty = data['boty']


            function StandardDeviation(numbersArr) {
                //--CALCULATE AVERAGE--
                var total = 0;
                for(var key in numbersArr)
                   total += numbersArr[key];
                var meanVal = total / numbersArr.length;
                //--CALCULATE AVERAGE--

                //--CALCULATE STANDARD DEVIATION--
                var SDprep = 0;
                for(var key in numbersArr)
                   SDprep += Math.pow((parseFloat(numbersArr[key]) - meanVal),2);
                var SDresult = Math.sqrt(SDprep/numbersArr.length);
                //--CALCULATE STANDARD DEVIATION--
                return SDresult;
            }

            function standardDev(window, y) {
                var sd = [];
                var x = window;
                while (x <= y.length) {
                    var a2c = y.slice(x - window, x);
                    var standev = StandardDeviation(a2c);
                    sd.push(standev);
                    x += 1;
                }
                return sd;
            }

            //moving average calc
            function movingAvg(array, count, qualifier){

                // calculate average for subarray
                var avg = function(array, qualifier){

                    var sum = 0, count = 0, val;
                    for (var i in array){
                        val = array[i];
                        if (!qualifier || qualifier(val)){
                            sum += val;
                            count++;
                        }
                    }

                    return sum / count;
                };

                var result = [], val;

                // pad beginning of result with null values
                for (var i=0; i < count-1; i++)
                    result.push(NaN);

                // calculate average for each subarray and add to result
                for (var i=0, len=array.length - count; i <= len; i++){

                    val = avg(array.slice(i, i + count), qualifier);
                    if (isNaN(val))
                        result.push(NaN);
                    else
                        result.push(val);
                }

                return result;
            }
            //end moving avg


            var top_band = [];
            var mid_band = [];
            var bot_band = [];

            var x = window;
            while (x < y.length) {
                var sma_array = movingAvg(y.slice(x - window, x), window);
                var sma_last = sma_array[sma_array.length - 1];

                var curSD = standardDev(window, y.slice(0, window));
                var curSD_last = curSD[curSD.length - 1];

                var tb = sma_last + curSD_last * 2;
                var bb = sma_last - curSD_last * 2;

                top_band.push(tb);
                mid_band.push(sma_last);
                bot_band.push(bb);
                x+=1;
                }

            if (top_band < topy) {
                shift_amt = topy.length - top_band.length;
                for (var q=0; q < shift_amt; q++) {
                    top_band.unshift(NaN);
                    mid_band.unshift(NaN);
                    bot_band.unshift(NaN);
                }
            }


            //for (var t=0; t < y.length; t++) {
            //   if (isNaN(top_band[0]) == true) {
            //        topy[t] = top_band[t + 1];
            //        boty[t] = bot_band[t + 1];
            //        midy[t] = mid_band[t + 1];
            //    }
            //    else {
            //        topy[t] = top_band[t];
            //        boty[t] = bot_band[t];
            //        midy[t] = mid_band[t];
            //    }
            //}
            for (var t=0; t < y.length; t++) {
                    topy[t] = top_band[t];
                    boty[t] = bot_band[t];
                    midy[t] = mid_band[t];
            }
            console.log(sources[i]);
            sources[i].change.emit();
        }
            """

    sourceArgs = {}
    for i in range(0, len(plot_line_list)):
        key = "source" + str(i)
        sourceArgs.update({key: source[i]})

    print(sourceArgs)

    SMAcallback = CustomJS(args=sourceArgs, code=sliderJS)

    SMAwindow_slider = Slider(start=1,
                              end=100,
                              value=20,
                              step=1,
                              title="SMA Window(period)",
                              callback=SMAcallback)

    # for space between checkboxes and buttons
    spacer = Spacer(height=100, width=50)

    # for temporary space when slider is invisible
    no_slider = Spacer(height=75, width=100)
    SMAwindow_slider.height = 65

    bollColumn = Column()
    bollColumn.width = 175
    bollColumn.children = [
        bollButton, no_slider, selectAllButton, deselectAllButton
    ]

    bollRow = Row(checkbox, spacer, bollColumn)

    # --------------------------------------------------------------
    # Allow bollinger button to turn on/off the slider

    # dynamicJSboll = '\ncolumn.children = [no_slider];'
    #
    # dynamicJSboll += """
    #                 if (cb_obj.active == true)
    #                 {
    #                     column.children = [boll_button, slider, select_all, deselect_all]
    #                 }
    #                 else if (cb_obj.active == false)
    #                 {
    #                     column.children = [boll_button, no_slider, select_all, deselect_all];
    #                 }"""

    key = "column"
    dictArgs.update({key: bollColumn})
    key = "boll_button"
    dictArgs.update({key: bollButton})
    key = "slider"
    dictArgs.update({key: SMAwindow_slider})
    key = "no_slider"
    dictArgs.update({key: no_slider})
    key = "select_all"
    dictArgs.update({key: selectAllButton})
    key = "deselect_all"
    dictArgs.update({key: deselectAllButton})

    # javascript for bollinger toggle button
    dynamicJSboll = """
    //console.log(cb_obj.active);
    if (cb_obj.active == true) {\n"""

    # slider is made visible
    dynamicJSboll += 'column.children = [boll_button, slider, select_all, deselect_all];\n'

    for t in range(0, len(plot_line_list)):
        dynamicJSboll += 'if (line' + str(t * 4) + '.visible == true) {\n'
        for i in range(3):
            dynamicJSboll += 'line' + str(t * 4 + i + 1) + '.visible = true;\n'
        dynamicJSboll += "}\n"

    dynamicJSboll += "}\n"
    dynamicJSboll += "else if (cb_obj.active == false) {\n"

    # slider is turned invisible
    dynamicJSboll += 'column.children = [boll_button, no_slider, select_all, deselect_all];\n'

    for t in range(0, len(plot_line_list)):
        for i in range(3):
            dynamicJSboll += 'line' + str(t * 4 + i +
                                          1) + '.visible = false;\n'
    dynamicJSboll += "}\n"

    bollButton.callback = CustomJS(args=dictArgs, code=dynamicJSboll)

    # --------------------------------------------------------------
    '''
    # display data tables only if there are 10 or less data sets
    if len(plotY) < 11:
        doc_layout = layout([
            [Column((plot), sizing_mode='scale_width')],
            [bollRow],
            [Row(children=data_table, sizing_mode='scale_width')],
        ], sizing_mode='scale_width')
    '''
    doc_layout = layout([[Column(plot)], [bollRow]], sizing_mode='scale_width')

    plots = [plot, [bollRow]]

    scripts, div = components(plot)

    cssCode = """
             <style type="text/css">

               svg {
                   font-family: 'Helvetica Neue', Helvetica;
               }

               .line {
                   fill: none;
                   stroke: #000;
                   stroke-width: 2px;
               }

               body {
                   height: 100%;
                   overflow: hidden;
                   margin: 0px;
                   display: flex;
                   box-sizing: border-box;
                   }

               h1 {
                   font-family: 'Helvetica Neue', Helvetica;
                   color: #ffc800;
                   text-align: center;
               }

               h2 {
                   font-family: 'Helvetica Neue', Helvetica;
                   color: grey;
                   text-align: center;
               }
               p {
                   font-family: 'Helvetica Neue', Helvetica;
                   font-size: 14px;
                   color: dark-grey;
                   text-align: justify;
               }
               metric {
                   font-family: 'Helvetica Neue', Helvetica;
                   font-size: 20px;
                   color: dark-grey;
                   text-decoration: underline;
                   text-align: center;
               }
               cop {
                   font-family: 'Helvetica Neue', Helvetica;
                   font-size: 10px;
                   color: black;
                   text-align: center;
               }

#main {
    transition: margin-left .5s;
    padding: 16px;
    margin-top: 70px;
    flex-grow: 1;
    display: flex;
    overflow-y: auto;  /*adds scroll to this container*/
    max-width: 100%;
}

.navbar {
  overflow: hidden;
  background-color: #ffc800;
  position: fixed;
  top: 0;
  width: 100%;
}

.navbar a {
  float: left;
  display: block;
  color: black;
  text-align: center;
  padding: 14px 16px;
  text-decoration: none;
  font-size: 15px;
}

.sidenav {
    max-height: 82%;
    width: 0;
    position: fixed;
    z-index: 1;
    top: 0;
    left: 0;
    background-color: #DCDCDC;
    overflow-x: hidden;
    overflow-y: auto;
    transition: 0.5s;
    padding-top: 30px;
    margin-top: 68px;
}

.sidenav a {
    padding: 8px 8px 8px 32px;
    text-decoration: none;
    font-size: 25px;
    color: white;
    display: block;
    transition: 0.3s;
}

.sidenav a:hover, .offcanvas a:focus{
    color: #ffc800;
}

.sidenav .closebtn {
    color: black;
    position: absolute;
    top: 0;
    right: 25px;
    color: black;
    font-size: 36px;
    margin-left: 50px;
}

                .table-custom {
                   border:1px;
                   border-style: solid;
                   border-color:#ffc800;
                   padding: 3em;
                   border-radius: 6px;
                   text-align:center;
                   margin: auto;
                   max-width: 100%;
                   max-height: 100%;
                   display: block;
               }
               .checkbox-scrollbar {
                   overflow: auto;
                   background-color: """ + str(checkboxColor) + """
               }

               @media screen and (max-height: 450px) {
  .sidenav {padding-top: 15px;}
  .sidenav a {font-size: 18px;}

           </style>
           """

    metrics_shown = ""
    reportId = fullDataset[0]["reportId"]
    counter = 1

    for element in fullDataset:
        if counter == 1:
            metrics_shown += "<b>Graph " + str(
                counter) + "</b><br>" + element["dataset"]["name"] + "<br>"
        else:
            metrics_shown += "<b><br>Graph " + str(
                counter) + "</b><br>" + element["dataset"]["name"] + "<br>"
        counter += 1

    redirect_head_script = """
        <script type="text/javascript">
          <!--
          if (screen.width <= 1200) {"""
    redirect_head_script += 'window.location = "https://s3.amazonaws.com/reports.tools.neonrisk.com/' + reportId + '/mobile_bokeh_report.html";'
    redirect_head_script += """}
          //-->
        </script>
        """

    toolbar_scripts = """
        <script>
    window.onload = function(){
          var pr = document.getElementById('print');
          pr.onclick = printReport;

          function printReport() {

            window.print();

          return false;
            }};

        </script>
        <script>
    window.onload = function(){
          var el = document.getElementById('email');
          el.onclick = createEmail;

          function createEmail() {

            var subject = "See the enclosed report"
            var link = "http://www.neonrisk.com"
            var body = "Please click here to access the report: " + link


            window.open('mailto:?subject=' + subject + '&body=' + body);

          return false;
            }};

        </script>
        <script>
    window.onload = function(){
          var sa = document.getElementById('saveAs');
          sa.onclick = saveAs;

          function saveAs() {

            alert("Please use the SaveAs function of your browser to save the document locally. Note however, that viewing the document always requires a connection.")

          return false;
            }};

        </script>
      <script>
        jQuery(function($) {
              $('#bookmark-this').click(function(e) {
                var bookmarkURL = window.location.href;
                var bookmarkTitle = document.title;

                if ('addToHomescreen' in window && addToHomescreen.isCompatible) {
                  // Mobile browsers
                  addToHomescreen({ autostart: false, startDelay: 0 }).show(true);
                } else if (window.sidebar && window.sidebar.addPanel) {
                  // Firefox <=22
                  window.sidebar.addPanel(bookmarkTitle, bookmarkURL, '');
                } else if ((window.sidebar && /Firefox/i.test(navigator.userAgent)) || (window.opera && window.print)) {
                  // Firefox 23+ and Opera <=14
                  $(this).attr({
                    href: bookmarkURL,
                    title: bookmarkTitle,
                    rel: 'sidebar'
                  }).off(e);
                  return true;
                } else if (window.external && ('AddFavorite' in window.external)) {
                  // IE Favorites
                  window.external.AddFavorite(bookmarkURL, bookmarkTitle);
                } else {
                  // Other browsers (mainly WebKit & Blink - Safari, Chrome, Opera 15+)
                  alert('Press ' + (/Mac/i.test(navigator.userAgent) ? 'Cmd' : 'Ctrl') + '+D to bookmark this page.');
                }

                return false;
              });
            });
        </script>
        """

    infoCol = """
               </head>

              <body>
                    <div class="navbar">
                    <a style="font-size:30px;cursor:pointer" onclick="openNav()">&#9776;</a>
          <a id="bookmark-this" href="#"><img src="https://s3.amazonaws.com/www.neonrisk.com/icons/bookmark.png" alt="Bookmark" width=30 height=30></a>
          <a href="#" title="Save this report as .pdf" id="saveAs">
          <img src="https://s3.amazonaws.com/www.neonrisk.com/icons/save.png" alt="Save this report as pdf" width=30 height=30></a>
          <a href="#" title="Print this report" id="print">
          <img src="https://s3.amazonaws.com/www.neonrisk.com/icons/print.png" alt="Print" width=30 height=30></a>"""

    linkToReport = 'https://s3.amazonaws.com/reports.tools.neonrisk.com/' + reportId + '/bokeh_report.html'

    infoCol += '<a href="mailto:?subject=Please%20see%20the%20enclosed%20report&body=Link%20to%20the%20report' + linkToReport + '">'

    infoCol += """<img src="https://s3.amazonaws.com/www.neonrisk.com/icons/email.png" alt="Email a link" width=30 height=30></a>

                    <a href="http://www.neonrisk.com"><img src="https://s3.amazonaws.com/www.neonrisk.com/icons/help.png" alt="Open Online Help" width=30 height=30></a>
                    <a href="https://www.linkedin.com/company/neon-risk"><img src="https://s3.amazonaws.com/www.neonrisk.com/icons/linkedin.png" alt="Find us on LinkedIn" width=30 height=30></a>
                    <a href="https://twitter.com/NeonRisk"><img src="https://s3.amazonaws.com/www.neonrisk.com/icons/twitter.png" alt="Find us on Twitter" width=30 height=30></a>
          </div>

                <div id="mySidenav" class="sidenav">
                       <a href="javascript:void(0)" class="closebtn" onclick="closeNav()">&times;</a>
                       <p><img src="http://www.neonrisk.com/uploads/6/9/5/2/69527361/hi-res-fpe-phat-flat-x4.png" alt="logo" align="left"></p>
                       <metric>Metrics shown</metric>"""

    infoCol += '<p>' + metrics_shown + '</p><br>'
    infoCol += '<p>Report # ' + reportId + '</p>'
    infoCol += """<p>Thank you for using Neon Risk Tools.
                       For support, please contact <a href="mailto:[email protected]">[email protected]</a></p>
                       <cop>copyright Neon Risk, Inc. 2017</cop>
                </div>
                <div id="main">
               """

    closeTableHTML = """
           </div>
                      <script>
function openNav() {
    document.getElementById("mySidenav").style.width = "250px";
    document.getElementById("main").style.marginLeft = "250px";
    document.getElementById("main").style.maxWidth = "87%";
}

function closeNav() {
    document.getElementById("mySidenav").style.width = "0";
    document.getElementById("main").style.marginLeft= "0";
    document.getElementById("main").style.maxWidth = "100%";
}
</script>
           </body>
           </html>
           """

    bokehCode = '<link href="https://cdnjs.cloudflare.com/ajax/libs/bokeh/1.0.2/bokeh.min.css" rel="stylesheet" type="text/css">'
    bokehCode += '<link href="https://cdnjs.cloudflare.com/ajax/libs/bokeh/1.0.2/bokeh-widgets.min.css" rel="stylesheet" type="text/css">'
    bokehCode += '<script src="https://cdnjs.cloudflare.com/ajax/libs/bokeh/1.0.2/bokeh.min.js"></script>'
    bokehCode += '<script src="https://cdnjs.cloudflare.com/ajax/libs/bokeh/1.0.2/bokeh-widgets.min.js"></script>'

    # -- NOW generate page

    reportBodyDataHTML_bokeh = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
    reportBodyDataHTML_bokeh += '<html xmlns="http://www.w3.org/1999/xhtml" style="height:100%;width:100%;font-size:100%">'
    reportBodyDataHTML_bokeh += '<head><meta content="text/html; charset=US-ASCII" http-equiv="Content-Type">'

    reportBodyDataHTML_bokeh += cssCode

    reportBodyDataHTML_bokeh += redirect_head_script + bokehCode + scripts + toolbar_scripts

    reportBodyDataHTML_bokeh += infoCol

    reportBodyDataHTML_bokeh += div

    reportBodyDataHTML_bokeh += closeTableHTML

    html_file = open("testing.html", "w")
    html_file.write(reportBodyDataHTML_bokeh)
    html_file.close()
    print(reportBodyDataHTML_bokeh)