Пример #1
0
def test_patches_hover_still_works_when_a_seleciton_is_preselcted(output_file_url, selenium):
    # This tests an edge case interaction when Patches (specifically) is used
    # with a tool that requires hit testing e.g. HitTool AND a selection is
    # pre-made on the data source driving it.
    plot = Plot(
        x_range=Range1d(0, 100),
        y_range=Range1d(0, 100),
        min_border=0
    )
    source = ColumnDataSource(dict(
        xs=[[0, 50, 50, 0], [50, 100, 100, 50]],
        ys=[[0, 0, 100, 100], [0, 0, 100, 100]],
        color=['pink', 'blue']
    ))
    source.selected = {
        '0d': {'glyph': None, 'indices': []},
        '1d': {'indices': [1]},
        '2d': {}
    }
    plot.add_glyph(source, Patches(xs='xs', ys='ys', fill_color='color'))
    plot.add_tools(HoverTool())
    plot.add_layout(LinearAxis(), 'below')
    plot.add_layout(LinearAxis(), 'left')
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Hover plot and test no error
    canvas = selenium.find_element_by_tag_name('canvas')
    actions = ActionChains(selenium)
    actions.move_to_element_with_offset(canvas, 100, 100)
    actions.perform()

    # If this assertion fails then there were likely errors on hover
    assert has_no_console_errors(selenium)
Пример #2
0
def test_line_rendering_with_selected_points(output_file_url, selenium,
                                             screenshot):
    plot = Plot(plot_height=400,
                plot_width=400,
                x_range=Range1d(0, 4),
                y_range=Range1d(-1, 1))

    x = [0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4]
    y = [
        0., 0.84147098, 0.90929743, 0.14112001, -0.7568025, -0.95892427,
        -0.2794155, 0.6569866, 0.98935825
    ]  # sin(2*x)

    source = ColumnDataSource(data=dict(x=x, y=y))
    plot.add_glyph(source, Circle(x='x', y='y'))
    plot.add_glyph(source, Line(x='x', y='y'))

    plot.add_tools(BoxSelectTool())

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Perform selection and take screenshot
    perform_box_selection(selenium, (0, 100), (400, 250))
    screenshot.assert_is_valid()
Пример #3
0
def test_legend_powered_by_source(output_file_url, selenium, screenshot):
    plot = Plot(height=HEIGHT,
                width=WIDTH,
                x_range=Range1d(0, 4),
                y_range=Range1d(0, 4),
                toolbar_location=None)
    source = ColumnDataSource(
        dict(
            x=[1, 2, 3],
            y=[1, 2, 3],
            color=['red', 'green', 'blue'],
            label=['Color Red', 'Color Green', 'Color Blue'],
        ))
    circle = Circle(x='x', y='y', fill_color='color', size=20)
    circle_renderer = plot.add_glyph(source, circle)
    plot.add_layout(
        Legend(items=[
            LegendItem(label=field('label'), renderers=[circle_renderer])
        ]))

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Take screenshot
    assert screenshot.is_valid()
Пример #4
0
def test_color_bar_placement_and_render(output_file_url, selenium, screenshot):
    plot = Plot(height=HEIGHT,
                width=WIDTH,
                x_range=Range1d(0, 10),
                y_range=Range1d(0, 10),
                toolbar_location=None)

    bar_vertical_right_panel = create_vertical_color_bar_with_log_cmap()
    bar_vertical_right_panel.location = (0, 0)

    bar_vertical_in_frame = create_vertical_color_bar_with_log_cmap()
    bar_vertical_in_frame.location = "top_right"
    bar_vertical_in_frame.title = "Dummy Title"
    bar_vertical_in_frame.title_standoff = 7

    bar_horizontal_below_panel = create_horizontal_color_bar_with_linear_cmap()
    bar_horizontal_below_panel.location = (0, 0)

    bar_horizontal_in_frame = create_horizontal_color_bar_with_linear_cmap()
    bar_horizontal_in_frame.location = "bottom_left"
    bar_horizontal_in_frame.title = "Dummy Title"

    plot.add_layout(bar_vertical_right_panel, 'right')
    plot.add_layout(bar_vertical_in_frame)
    plot.add_layout(bar_horizontal_below_panel, 'below')
    plot.add_layout(bar_horizontal_in_frame)

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Take screenshot
    assert screenshot.is_valid()
Пример #5
0
def test_lasso_select(output_file_url, selenium):
    plot = generate_plot()

    #limit to one callback on click release
    plot.add_tools(LassoSelectTool(select_every_mousemove=False))

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Drag a lasso selection area around middle point
    canvas = selenium.find_element_by_tag_name('canvas')

    actions = ActionChains(selenium)
    actions.move_to_element_with_offset(canvas, PLOT_DIM * 0.25, PLOT_DIM * 0.25)
    actions.click_and_hold()
    actions.move_by_offset(0, PLOT_DIM * 0.5)
    actions.move_by_offset(PLOT_DIM * 0.5, 0)
    actions.move_by_offset(0, PLOT_DIM * -0.5)
    actions.release()
    actions.perform()

    # Get the alert from box select and assert that the middle item is selected
    alert = selenium.switch_to_alert()
    assert alert.text == 'middle'
Пример #6
0
def test_label(output_file_url, selenium, screenshot):

    # Have to specify x/y range as labels aren't included in the plot area solver
    plot = Plot(plot_height=HEIGHT, plot_width=WIDTH,
                x_range=Range1d(0, 10), y_range=Range1d(0, 10),
                toolbar_location=None)

    label1 = Label(x=1, y=6, x_offset=25, y_offset=25,
                   text="Demo Label",
                   text_font_size='38pt', text_color='red', text_alpha=0.9,
                   text_baseline='bottom', text_align='left',
                   background_fill_color='green', background_fill_alpha=0.2,
                   angle=15, angle_units='deg',
                   render_mode='canvas')

    label2 = Label(x=3, y=5.5, text="(I'm Canvas)", text_font_size='20pt',
                   border_line_color='black', border_line_width=2, border_line_dash='8 4',
                   render_mode='canvas')

    label3 = Label(x=1, y=2, x_offset=25, y_offset=25,
                   text="Demo Label",
                   text_font_size='38pt', text_color='red', text_alpha=0.9,
                   text_baseline='bottom', text_align='left',
                   background_fill_color='green', background_fill_alpha=0.2,
                   angle=0.261, angle_units='rad',
                   render_mode='css')

    label4 = Label(x=3, y=1.0, text="(I'm CSS)", text_font_size='20pt',
                   border_line_color='black', border_line_width=2, border_line_dash='8 4',
                   render_mode='css')

    label_above = Label(
        x=0, y=0, text="Label in above panel", x_units='screen', y_units='screen',
        text_font_size='38pt', text_color='firebrick', text_alpha=0.9,
    )

    label_left = Label(
        x=0, y=0, text="Label in left panel",
        x_units='screen', y_units='screen', angle=90, angle_units='deg',
        text_font_size='18pt', text_color='firebrick', text_alpha=0.9,
        background_fill_color='aliceblue', text_baseline='top',
    )

    plot.add_layout(LinearAxis(), 'below')
    plot.add_layout(LinearAxis(), 'left')

    plot.add_layout(label1)
    plot.add_layout(label2)
    plot.add_layout(label3)
    plot.add_layout(label4)
    plot.add_layout(label_above, 'above')
    plot.add_layout(label_left, 'left')

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Take screenshot
    assert screenshot.is_valid()
Пример #7
0
def test_color_bar_placement_and_render(output_file_url, selenium, screenshot):
    plot = Plot(height=HEIGHT, width=WIDTH,
                x_range=Range1d(0,10), y_range=Range1d(0,10),
                toolbar_location=None)

    bar_vertical_right_panel = create_vertical_color_bar_with_log_cmap()
    bar_vertical_right_panel.location = (0, 0)

    bar_vertical_in_frame = create_vertical_color_bar_with_log_cmap()
    bar_vertical_in_frame.location = "top_right"
    bar_vertical_in_frame.title = "Dummy Title"
    bar_vertical_in_frame.title_standoff = 7

    bar_horizontal_below_panel = create_horizontal_color_bar_with_linear_cmap()
    bar_horizontal_below_panel.location = (0, 0)

    bar_horizontal_in_frame = create_horizontal_color_bar_with_linear_cmap()
    bar_horizontal_in_frame.location = "bottom_left"
    bar_horizontal_in_frame.title = "Dummy Title"

    plot.add_layout(bar_vertical_right_panel, 'right')
    plot.add_layout(bar_vertical_in_frame)
    plot.add_layout(bar_horizontal_below_panel, 'below')
    plot.add_layout(bar_horizontal_in_frame)

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Take screenshot
    screenshot.assert_is_valid()
Пример #8
0
def test_arrow(output_file_url, selenium, screenshot):

    # Have to specify x/y range as labels aren't included in the plot area solver
    plot = figure(height=HEIGHT, width=WIDTH, x_range=(0,10), y_range=(0,10), tools='', toolbar_location="above")

    arrow1 = Arrow(x_start=1, y_start=3, x_end=6, y_end=8,
                   line_color='green', line_alpha=0.7,
                   line_dash='8 4', line_width=5, end=OpenHead()
                   )
    arrow1.end.line_width=8

    arrow2 = Arrow(x_start=2, y_start=2, x_end=7, y_end=7,
                   start=NormalHead(), end=VeeHead()
                   )
    arrow2.start.fill_color = 'indigo'
    arrow2.end.fill_color = 'orange'
    arrow2.end.size = 50

    plot.add_layout(arrow1)
    plot.add_layout(arrow2)

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Take screenshot
    assert screenshot.is_valid()
Пример #9
0
def test_label(output_file_url, selenium, screenshot):

    # Have to specify x/y range as labels aren't included in the plot area solver
    plot = Plot(plot_height=HEIGHT, plot_width=WIDTH,
                x_range=Range1d(0, 10), y_range=Range1d(0, 10),
                toolbar_location=None)

    label1 = Label(x=1, y=6, x_offset=25, y_offset=25,
                   text="Demo Label",
                   text_font_size='38pt', text_color='red', text_alpha=0.9,
                   text_baseline='bottom', text_align='left',
                   background_fill_color='green', background_fill_alpha=0.2,
                   angle=15, angle_units='deg',
                   render_mode='canvas')

    label2 = Label(x=3, y=5.5, text="(I'm Canvas)", text_font_size='20pt',
                   border_line_color='black', border_line_width=2, border_line_dash='8 4',
                   render_mode='canvas')

    label3 = Label(x=1, y=2, x_offset=25, y_offset=25,
                   text="Demo Label",
                   text_font_size='38pt', text_color='red', text_alpha=0.9,
                   text_baseline='bottom', text_align='left',
                   background_fill_color='green', background_fill_alpha=0.2,
                   angle=0.261, angle_units='rad',
                   render_mode='css')

    label4 = Label(x=3, y=1.0, text="(I'm CSS)", text_font_size='20pt',
                   border_line_color='black', border_line_width=2, border_line_dash='8 4',
                   render_mode='css')

    label_above = Label(
        x=0, y=0, text="Label in above panel", x_units='screen', y_units='screen',
        text_font_size='38pt', text_color='firebrick', text_alpha=0.9,
    )

    label_left = Label(
        x=0, y=0, text="Label in left panel",
        x_units='screen', y_units='screen', angle=90, angle_units='deg',
        text_font_size='18pt', text_color='firebrick', text_alpha=0.9,
        background_fill_color='aliceblue', text_baseline='top',
    )

    plot.add_layout(LinearAxis(), 'below')
    plot.add_layout(LinearAxis(), 'left')

    plot.add_layout(label1)
    plot.add_layout(label2)
    plot.add_layout(label3)
    plot.add_layout(label4)
    plot.add_layout(label_above, 'above')
    plot.add_layout(label_left, 'left')

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Take screenshot
    screenshot.assert_is_valid()
Пример #10
0
def test_lasso_select(output_file_url, selenium):
    plot = generate_plot()

    #limit to one callback on click release
    plot.add_tools(LassoSelectTool(select_every_mousemove=False))

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Drag a lasso selection area around middle point
    canvas = selenium.find_element_by_tag_name('canvas')

    actions = ActionChains(selenium)
    actions.move_to_element_with_offset(canvas, PLOT_DIM * 0.25, PLOT_DIM * 0.25)
    actions.click_and_hold()
    actions.move_by_offset(0, PLOT_DIM * 0.5)
    actions.move_by_offset(PLOT_DIM * 0.5, 0)
    actions.move_by_offset(0, PLOT_DIM * -0.5)
    actions.release()
    actions.perform()

    # Get the alert from box select and assert that the middle item is selected
    alert = selenium.switch_to_alert()
    assert alert.text == 'middle'
Пример #11
0
def test_hover_changes_color(output_file_url, selenium, screenshot):

    # Make plot and add a taptool callback that generates an alert
    plot = figure(height=HEIGHT,
                  width=WIDTH,
                  tools='',
                  toolbar_location="above")
    rect = plot.rect(x=[1, 2],
                     y=[1, 1],
                     width=1,
                     height=1,
                     fill_color='cyan',
                     hover_fill_color='magenta',
                     line_color=None,
                     hover_line_color=None)
    plot.add_tools(HoverTool(tooltips=None, renderers=[rect]))

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Hover over plot and take screenshot
    canvas = selenium.find_element_by_tag_name('canvas')
    hover_at_position(selenium, canvas, WIDTH * 0.33, HEIGHT * 0.5)
    assert screenshot.is_valid()
Пример #12
0
def test_y_range_does_not_pan_below_y_min(output_file_url, selenium):
    y_range_min = -1
    plot = make_plot(yr=Range1d(0, 3, bounds=(y_range_min, None)))
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Pan plot and test for new range value
    pan_plot(selenium, pan_x=50, pan_y=-150)
    new_range_start = float(selenium.execute_script("""alert(Bokeh.index['plot-id'].model.y_range.start)"""))
    selenium.switch_to_alert().dismiss()  # This is not necessary but assists debugging
    assert round(new_range_start) == y_range_min
Пример #13
0
def test_x_range_does_not_pan_right_of_x_max(output_file_url, selenium):
    x_range_max = 4
    plot = make_plot(xr=Range1d(0, 3, bounds=(None, x_range_max)))
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Pan plot and test for new range value
    pan_plot(selenium, pan_x=-150, pan_y=0)
    new_range_end = float(selenium.execute_script("""alert(Bokeh.index['plot-id'].model.x_range.end)"""))
    selenium.switch_to_alert().dismiss()  # This is not necessary but assists debugging
    assert round(new_range_end) == x_range_max
Пример #14
0
def test_reversed_x_range_does_not_pan_right_of_x_min(output_file_url, selenium):
    x_range_min = -1
    plot = make_plot(xr=Range1d(3, 0, bounds=(x_range_min, None)))
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Pan plot and test for new range value
    pan_plot(selenium, pan_x=-150, pan_y=0)
    new_range_start = float(selenium.execute_script("""alert(Bokeh.index['plot-id'].model.x_range.min)"""))
    selenium.switch_to_alert().dismiss()
    assert round(new_range_start) == x_range_min
Пример #15
0
def test_x_range_does_not_pan_left_of_x_min(output_file_url, selenium):
    x_range_min = -1
    plot = make_pan_plot_with_callback(xr=Range1d(0, 3, bounds=(x_range_min, None)))
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Pan plot and test for new range value
    pan_plot(selenium, pan_x=200, pan_y=0)
    new_range_start = float(selenium.execute_script("""alert(window.get_x_range_start())"""))
    selenium.switch_to_alert().dismiss()
    assert round(new_range_start) == x_range_min
Пример #16
0
def test_reversed_y_range_does_not_pan_below_y_max(output_file_url, selenium):
    y_range_max = 4
    plot = make_pan_plot_with_callback(yr=Range1d(3, 0, bounds=(None, y_range_max)))
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Pan plot and test for new range value
    pan_plot(selenium, pan_x=50, pan_y=-150)
    new_range_end = float(selenium.execute_script("""alert(window.get_y_range_start())"""))
    selenium.switch_to_alert().dismiss()
    assert round(new_range_end) == y_range_max
Пример #17
0
def test_y_range_does_not_pan_above_y_max(output_file_url, selenium):
    y_range_max = 4
    plot = make_pan_plot_with_callback(yr=Range1d(0, 3, bounds=(None, y_range_max)))
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Pan plot and test for new range value
    pan_plot(selenium, pan_x=50, pan_y=150)
    new_range_end = float(selenium.execute_script("""alert(window.get_y_range_end())"""))
    selenium.switch_to_alert().dismiss()  # This is not necessary but assists debugging
    assert round(new_range_end) == y_range_max
Пример #18
0
def test_reversed_x_range_does_not_pan_left_of_x_max(output_file_url, selenium):
    x_range_max = 4
    plot = make_pan_plot_with_callback(xr=Range1d(3, 0, bounds=(None, x_range_max)))
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Pan plot and test for new range value
    pan_plot(selenium, pan_x=200, pan_y=0)
    new_range_end = float(selenium.execute_script("""alert(window.get_x_range_start())"""))
    selenium.switch_to_alert().dismiss()  # This is not necessary but assists debugging
    assert round(new_range_end) == x_range_max
Пример #19
0
def test_reversed_y_range_does_not_pan_below_y_max(output_file_url, selenium):
    y_range_max = 4
    plot = make_pan_plot_with_callback(yr=Range1d(3, 0, bounds=(None, y_range_max)))
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Pan plot and test for new range value
    pan_plot(selenium, pan_x=50, pan_y=-150)
    new_range_end = float(selenium.execute_script("""alert(window.get_y_range_start())"""))
    selenium.switch_to_alert().dismiss()
    assert round(new_range_end) == y_range_max
Пример #20
0
def test_y_range_does_not_pan_above_y_max(output_file_url, selenium):
    y_range_max = 4
    plot = make_pan_plot_with_callback(yr=Range1d(0, 3, bounds=(None, y_range_max)))
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Pan plot and test for new range value
    pan_plot(selenium, pan_x=50, pan_y=150)
    new_range_end = float(selenium.execute_script("""alert(window.get_y_range_end())"""))
    selenium.switch_to_alert().dismiss()  # This is not necessary but assists debugging
    assert round(new_range_end) == y_range_max
Пример #21
0
def test_reversed_x_range_does_not_pan_left_of_x_max(output_file_url, selenium):
    x_range_max = 4
    plot = make_pan_plot_with_callback(xr=Range1d(3, 0, bounds=(None, x_range_max)))
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Pan plot and test for new range value
    pan_plot(selenium, pan_x=200, pan_y=0)
    new_range_end = float(selenium.execute_script("""alert(window.get_x_range_start())"""))
    selenium.switch_to_alert().dismiss()  # This is not necessary but assists debugging
    assert round(new_range_end) == x_range_max
Пример #22
0
def test_selection_tool_make_selection(output_file_url, selenium):
    plot = make_plot()

    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    perform_box_selection(selenium, (50, 200), (450, 400))

    code = "return Bokeh.index['plot-id'].model.select_one('rect-glyph').data_source.selected['1d'].indices"
    selected = selenium.execute_script(code)
    assert selected == [0, 1]
Пример #23
0
def test_selection_tool_make_selection(output_file_url, selenium):
    plot = make_plot()

    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    perform_box_selection(selenium, (50, 200), (450, 400))

    code = "return Bokeh.index['plot-id'].model.select_one('rect-glyph').data_source.selected['1d'].indices"
    selected = selenium.execute_script(code)
    assert selected == [0, 1]
Пример #24
0
def test_x_range_does_not_pan_left_of_x_min(output_file_url, selenium):
    x_range_min = -1
    plot = make_pan_plot_with_callback(xr=Range1d(0, 3, bounds=(x_range_min, None)))
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Pan plot and test for new range value
    pan_plot(selenium, pan_x=200, pan_y=0)
    new_range_start = float(selenium.execute_script("""alert(window.get_x_range_start())"""))
    selenium.switch_to_alert().dismiss()
    assert round(new_range_start) == x_range_min
Пример #25
0
def test_no_border_or_background_fill(output_file_url, selenium, screenshot):

    # Have body background-color that should appear through the no-fill plot
    template = Template("""
    <!doctype html>
    <html lang="en">
    <head>
        {{ bokeh_js }}
        {{ bokeh_css}}
        <style>
            body { background-color: lightblue; }
        </style>
    </head>
    <body>
        {{ plot_script }}
        {{ plot_div }}
    </body>
    </html>
    """)

    plot = Plot(plot_height=HEIGHT,
                plot_width=WIDTH,
                x_range=Range1d(0, 10),
                y_range=Range1d(0, 10),
                toolbar_location=None)

    # This is the no-fill that we're testing
    plot.background_fill_color = None
    plot.border_fill_color = None

    plot.add_glyph(Circle(x=3, y=3, size=50, fill_color='#ffffff'))
    plot.add_glyph(Circle(x=6, y=6, size=50, fill_color='#ffffff'))

    plot.add_layout(
        LinearAxis(major_label_text_color='#ffffff',
                   major_label_text_font_size="30pt"), 'left')
    plot.add_layout(
        LinearAxis(major_label_text_color='#ffffff',
                   major_label_text_font_size="30pt"), 'below')

    html = file_html(plot, INLINE, template=template)

    # filename has to match test function + '.html' light
    filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                            "test_no_border_or_background_fill.html")

    with io.open(filepath, "w", encoding="utf-8") as f:
        f.write(decode_utf8(html))

    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)
    assert screenshot.is_valid()
Пример #26
0
def test_selection_tool_selection_ending_outside_frame_makes_selection(output_file_url, selenium):
    plot = make_plot()

    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # make selection ending outside of frame
    perform_box_selection(selenium, (50, 50), (1000, 1000))

    code = "return Bokeh.index['plot-id'].model.select_one('rect-glyph').data_source.selected['1d'].indices"
    selected = selenium.execute_script(code)
    assert selected == [0,1,2]
def test_patches_hover_still_works_when_a_seleciton_is_preselcted(
        output_file_url, selenium):
    # This tests an edge case interaction when Patches (specifically) is used
    # with a tool that requires hit testing e.g. HitTool AND a selection is
    # pre-made on the data source driving it.
    plot = Plot(x_range=Range1d(0, 100), y_range=Range1d(0, 100), min_border=0)
    source = ColumnDataSource(
        dict(xs=[[0, 50, 50, 0], [50, 100, 100, 50]],
             ys=[[0, 0, 100, 100], [0, 0, 100, 100]],
             color=['pink', 'blue']))
    source.selected = {
        '0d': {
            'glyph': None,
            'indices': []
        },
        '1d': {
            'indices': [1]
        },
        '2d': {
            'indices': {}
        },
    }
    plot.add_glyph(source, Patches(xs='xs', ys='ys', fill_color='color'))
    plot.add_tools(HoverTool())
    plot.add_layout(LinearAxis(), 'below')
    plot.add_layout(LinearAxis(), 'left')
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Hover plot and test no error
    canvas = selenium.find_element_by_tag_name('canvas')
    actions = ActionChains(selenium)
    actions.move_to_element_with_offset(canvas, 100, 100)
    actions.perform()

    # If this assertion fails then there were likely errors on hover
    assert has_no_console_errors(selenium)
def test_no_border_or_background_fill(output_file_url, selenium, screenshot):

    # Have body background-color that should appear through the no-fill plot
    template = Template("""
    <!doctype html>
    <html lang="en">
    <head>
        {{ bokeh_js }}
        {{ bokeh_css}}
        <style>
            body { background-color: lightblue; }
        </style>
    </head>
    <body>
        {{ plot_script }}
        {{ plot_div }}
    </body>
    </html>
    """)

    plot = Plot(plot_height=HEIGHT, plot_width=WIDTH,
                x_range=Range1d(0, 10), y_range=Range1d(0, 10),
                toolbar_location=None)

    # This is the no-fill that we're testing
    plot.background_fill_color = None
    plot.border_fill_color = None

    plot.add_glyph(Circle(x=3, y=3, size=50, fill_color='#ffffff'))
    plot.add_glyph(Circle(x=6, y=6, size=50, fill_color='#ffffff'))

    plot.add_layout(LinearAxis(major_label_text_color='#ffffff',
                               major_label_text_font_size="30pt"),
                    'left')
    plot.add_layout(LinearAxis(major_label_text_color='#ffffff',
                               major_label_text_font_size="30pt"),
                    'below')

    html = file_html(plot, INLINE, template=template)

    # filename has to match test function + '.html' light
    filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                            "test_no_border_or_background_fill.html")

    with io.open(filepath, "w", encoding="utf-8") as f:
        f.write(decode_utf8(html))

    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)
    screenshot.assert_is_valid()
Пример #29
0
def test_selection_tool_selection_ending_outside_frame_stops_selection(
        output_file_url, selenium):
    plot = make_plot()

    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # make selection ending outside of frame
    perform_box_selection(selenium, (50, 50), (1000, 1000))

    code = "return Bokeh.index['plot-id'].model.select_one('rect-glyph').data_source.selected['1d'].indices"
    selected = selenium.execute_script(code)
    assert selected == []
def test_band(output_file_url, selenium, screenshot):

    x_range = Range1d(0, 10)
    y_range = Range1d(0, 10)

    # Have to specify x/y range as labels aren't included in the plot area solver
    plot = Plot(plot_height=HEIGHT,
                plot_width=WIDTH,
                x_range=x_range,
                y_range=y_range,
                toolbar_location=None)

    source = ColumnDataSource(data=dict(
        x1=[1, 3, 5, 7, 9],
        lower1=[1, 2, 1, 2, 1],
        upper1=[2, 3, 2, 3, 2],
        x2=[200, 250, 350, 450, 550],
        lower2=[400, 300, 400, 300, 400],
        upper2=[500, 400, 500, 400, 500],
    ))

    band1 = Band(base='x1',
                 lower='lower1',
                 upper='upper1',
                 line_width=3,
                 line_color='red',
                 line_dash='dashed',
                 source=source)
    band2 = Band(base='x2',
                 lower='lower2',
                 upper='upper2',
                 base_units='screen',
                 lower_units='screen',
                 upper_units='screen',
                 dimension='width',
                 line_width=3,
                 fill_color='blue',
                 line_color='green',
                 source=source)

    plot.add_layout(band1)
    plot.add_layout(band2)

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Take screenshot
    screenshot.assert_is_valid()
Пример #31
0
def test_wheel_zoom_is_deselected_by_default(output_file_url, selenium):

    # Make plot and add a taptool callback that generates an alert
    plot = make_plot()

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Tap the plot and test for alert
    scroll_button = get_non_stale_scroll_button(selenium)
    scroll_classes = scroll_button.get_attribute('class')
    assert 'active' not in scroll_classes
Пример #32
0
def test_visible_property_hides_things_correctly(output_file_url, selenium, screenshot):

    plot = figure(toolbar_location=None)
    l1 = plot.line([1, 2, 3], [1, 2, 3])
    l2 = plot.line([1, 2, 3], [2, 4, 6])

    plot.xaxis.visible = False
    plot.ygrid.visible = False
    l1.visible = False

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)
    assert screenshot.is_valid()
Пример #33
0
def test_visible_property_hides_things_correctly(output_file_url, selenium, screenshot):

    plot = figure()
    l1 = plot.line([1, 2, 3], [1, 2, 3])
    l2 = plot.line([1, 2, 3], [2, 4, 6])

    plot.xaxis.visible = False
    plot.ygrid.visible = False
    l1.visible = False

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)
    assert screenshot.is_valid()
Пример #34
0
def test_reversed_y_range_does_not_pan_above_y_min(output_file_url, selenium):
    y_range_min = -1
    plot = make_plot(yr=Range1d(3, 0, bounds=(y_range_min, None)))
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Pan plot and test for new range value
    pan_plot(selenium, pan_x=50, pan_y=150)

    new_range_start = float(
        selenium.execute_script(
            """alert(Bokeh.index['plot-id'].model.y_range.min)"""))
    selenium.switch_to_alert().dismiss()
    assert round(new_range_start) == y_range_min
Пример #35
0
def test_y_range_does_not_pan_below_y_min(output_file_url, selenium):
    y_range_min = -1
    plot = make_plot(yr=Range1d(0, 3, bounds=(y_range_min, None)))
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Pan plot and test for new range value
    pan_plot(selenium, pan_x=50, pan_y=-150)
    new_range_start = float(
        selenium.execute_script(
            """alert(Bokeh.index['plot-id'].model.y_range.start)"""))
    selenium.switch_to_alert().dismiss(
    )  # This is not necessary but assists debugging
    assert round(new_range_start) == y_range_min
Пример #36
0
def test_range_with_callback_triggers_alert(output_file_url, selenium):
    # Simple test to ensure range callbacks are working
    # Rest of tests in this file depend on range callback.

    plot = make_pan_plot_with_callback()
    initial_start = plot.x_range.start
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Pan plot and test for new range value
    pan_plot(selenium, pan_x=100, pan_y=100)
    new_range_start = float(selenium.execute_script("""alert(window.get_x_range_start())"""))
    selenium.switch_to_alert().dismiss()
    assert new_range_start < initial_start
Пример #37
0
def test_x_range_does_not_pan_right_of_x_max(output_file_url, selenium):
    x_range_max = 4
    plot = make_plot(xr=Range1d(0, 3, bounds=(None, x_range_max)))
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Pan plot and test for new range value
    pan_plot(selenium, pan_x=-150, pan_y=0)
    new_range_end = float(
        selenium.execute_script(
            """alert(Bokeh.index['plot-id'].model.x_range.end)"""))
    selenium.switch_to_alert().dismiss(
    )  # This is not necessary but assists debugging
    assert round(new_range_end) == x_range_max
Пример #38
0
def test_scale_width_chart_starts_at_correct_size(output_file_url, selenium):
    hist = Histogram(df['mpg'], title="MPG Distribution", sizing_mode='scale_width')
    save(hist)

    selenium.set_window_size(width=1000, height=600)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    canvas = selenium.find_element_by_tag_name('canvas')
    wait_for_canvas_resize(canvas, selenium)

    # Canvas width should be just under 1000 * 0.9
    # (default file_html has a body width of 90%)
    assert canvas.size['width'] > 850
    assert canvas.size['width'] < 900
Пример #39
0
def test_scale_width_plot_starts_at_correct_size(output_file_url, selenium):
    plot = make_sizing_mode_plot(600, 600, sizing_mode='scale_width')
    save(plot)

    selenium.set_window_size(width=1000, height=600)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    canvas = selenium.find_element_by_tag_name('canvas')
    wait_for_canvas_resize(canvas, selenium)

    # Canvas width should be just under 1000 * 0.9
    # (default file_html has a body width of 90%)
    assert canvas.size['width'] > 850
    assert canvas.size['width'] < 900
Пример #40
0
def test_responsive_chart_starts_at_correct_size(output_file_url, selenium):
    hist = Histogram(df['mpg'], title="MPG Distribution", responsive=True)
    save(hist)

    selenium.set_window_size(width=1000, height=600)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    canvas = selenium.find_element_by_tag_name('canvas')
    wait_for_canvas_resize(canvas, selenium)

    # Canvas width should be just under 1000 * 0.9
    # (default file_html has a body width of 90%)
    assert canvas.size['width'] > 850
    assert canvas.size['width'] < 900
Пример #41
0
def test_scale_width_maintains_a_minimum_height(output_file_url, selenium):
    # The aspect ratio is landscape but should not allow a height less than 100
    plot = make_sizing_mode_plot(1200, 600, sizing_mode='scale_width')
    save(plot)

    # Open the browser with the plot and resize the window small
    selenium.set_window_size(width=100, height=600)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)
    canvas = selenium.find_element_by_tag_name('canvas')
    wait_for_canvas_resize(canvas, selenium)

    # Plot should have been shrunk somewhat
    assert canvas.size['height'] < 600
    assert canvas.size['height'] >= 100
Пример #42
0
def test_range_with_callback_triggers_alert(output_file_url, selenium):
    # Simple test to ensure range callbacks are working
    # Rest of tests in this file depend on range callback.

    plot = make_pan_plot_with_callback()
    initial_start = plot.x_range.start
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Pan plot and test for new range value
    pan_plot(selenium, pan_x=100, pan_y=100)
    new_range_start = float(selenium.execute_script("""alert(window.get_x_range_start())"""))
    selenium.switch_to_alert().dismiss()
    assert new_range_start < initial_start
Пример #43
0
def test_scale_width_plot_starts_at_correct_size(output_file_url, selenium):
    plot = make_sizing_mode_plot(600, 600, sizing_mode='scale_width')
    save(plot)

    selenium.set_window_size(width=1000, height=600)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    canvas = selenium.find_element_by_tag_name('canvas')
    wait_for_canvas_resize(canvas, selenium)

    # Canvas width should be just under 1000 * 0.9
    # (default file_html has a body width of 90%)
    assert canvas.size['width'] > 850
    assert canvas.size['width'] < 900
Пример #44
0
def test_scale_width_maintains_a_minimum_height(output_file_url, selenium):
    # The aspect ratio is landscape but should not allow a height less than 100
    plot = make_sizing_mode_plot(1200, 600, sizing_mode='scale_width')
    save(plot)

    # Open the browser with the plot and resize the window small
    selenium.set_window_size(width=100, height=600)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)
    canvas = selenium.find_element_by_tag_name('canvas')
    wait_for_canvas_resize(canvas, selenium)

    # Plot should have been shrunk somewhat
    assert canvas.size['height'] < 600
    assert canvas.size['height'] >= 100
Пример #45
0
def test_box_select(output_file_url, selenium):
    PLOT_DIM = 600

    source = ColumnDataSource(
        dict(
            x=[1, 2, 3],
            y=[3, 2, 3],
            name=['top_left', 'middle', 'top_right'],
        ))
    # Make plot and add a taptool callback that generates an alert
    plot = figure(tools='box_select',
                  height=PLOT_DIM,
                  width=PLOT_DIM,
                  x_range=[1, 3],
                  y_range=[1, 3])
    plot.circle(x='x', y='y', radius=0.2, source=source)

    source.callback = CustomJS(code="""
        var indices = cb_obj.get('selected')['1d'].indices,
            data = cb_obj.get('data'),
            selected_names = '';

        Bokeh.$.each(indices, function(i, index) {
            selected_names += data['name'][index];
        });

        alert(selected_names);
    """)

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Drag a box zoom around middle point
    canvas = selenium.find_element_by_tag_name('canvas')

    actions = ActionChains(selenium)
    actions.move_to_element_with_offset(canvas, PLOT_DIM * 0.25,
                                        PLOT_DIM * 0.25)
    actions.click_and_hold()
    actions.move_by_offset(PLOT_DIM * 0.5, PLOT_DIM * 0.5)
    actions.release()
    actions.perform()

    # Get the alert from box select and assert that the middle item is selected
    alert = selenium.switch_to_alert()
    assert alert.text == 'middle'
Пример #46
0
def test_selection_tool_multiselection_with_shift(output_file_url, selenium):
    plot = make_plot()

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # make first selection
    perform_box_selection(selenium, (50, 200), (250, 400))
    # make second, multi-selection with shift
    perform_box_selection(selenium, (475, 200), (275, 400), hold_shift=True)

    code = "return Bokeh.index['plot-id'].model.select_one('rect-glyph').data_source.selected['1d'].indices"
    selected = selenium.execute_script(code)
    assert selected == [0, 2]
Пример #47
0
def test_selection_tool_multiselection_with_shift(output_file_url, selenium):
    plot = make_plot()

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # make first selection
    perform_box_selection(selenium, (50, 200), (250, 400))
    # make second, multi-selection with shift
    perform_box_selection(selenium, (475, 200), (275, 400), hold_shift=True)

    code = "return Bokeh.index['plot-id'].model.select_one('rect-glyph').data_source.selected['1d'].indices"
    selected = selenium.execute_script(code)
    assert selected == [0, 2]
Пример #48
0
def test_scale_width_resizes_plot_while_maintaining_aspect_ratio(
        output_file_url, selenium):

    # We want the aspect ratio of the initial plot to be maintained, but we
    # can't measure it perfectly so we test against bounds.
    aspect_ratio = 2
    plot_height = 400
    plot_width = 400 * aspect_ratio
    lower_bound = aspect_ratio * 0.95
    upper_bound = aspect_ratio * 1.05

    # In this test we tell selenium what to set the browser window to be
    # initially and then finally so we can test that the canvas has
    # scaled down by approximately the correct amount.
    initial_window_width = 1200
    final_window_width = 600

    # Make the plot with autoresize
    plot = make_sizing_mode_plot(plot_width,
                                 plot_height,
                                 sizing_mode='scale_width')
    save(plot)

    # Open the browser with the plot and resize the window to get an initial measure
    selenium.set_window_size(width=initial_window_width, height=600)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)
    canvas = selenium.find_element_by_tag_name('canvas')
    wait_for_canvas_resize(canvas, selenium)

    initial_height = canvas.size['height']
    initial_width = canvas.size['width']
    initial_aspect_ratio = initial_width / initial_height
    assert initial_aspect_ratio > lower_bound
    assert initial_aspect_ratio < upper_bound

    # Now resize to a smaller window size and check again
    selenium.set_window_size(width=final_window_width, height=600)
    selenium.set_window_size(width=final_window_width,
                             height=599)  # See note (1) below
    wait_for_canvas_resize(canvas, selenium)

    final_height = canvas.size['height']
    final_width = canvas.size['width']
    final_aspect_ratio = final_width / final_height
    assert final_aspect_ratio > lower_bound
    assert final_aspect_ratio < upper_bound
Пример #49
0
def test_tap_with_callback_triggers_alert(output_file_url, selenium):

    # Make plot and add a taptool callback that generates an alert
    plot = make_plot('tap')
    tap = plot.select(dict(type=TapTool))[0]
    tap.callback = CustomJS(code='alert("tapped")')

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Tap the plot and test for alert
    canvas = selenium.find_element_by_tag_name('canvas')
    click_glyph_at_position(selenium, canvas, 250, 400)
    alert = selenium.switch_to_alert()
    assert alert.text == 'tapped'
Пример #50
0
def test_reset_triggers_range_callback(output_file_url, selenium):

    # Make plot and add a range callback that generates an alert
    plot = make_plot('reset')
    range1d = plot.select(dict(type=Range1d))[0]
    range1d.callback = CustomJS(code='alert("plot reset")')

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Tap the plot and test for alert
    reset_button = selenium.find_element_by_class_name('bk-tool-icon-reset')
    click_element_at_position(selenium, reset_button, 10, 10)
    alert = selenium.switch_to_alert()
    assert alert.text == 'plot reset'
def test_data_table_preselection_python(output_file_url, selenium, screenshot):

    data = dict(x = list(range(10)))
    selected = { '0d': {'glyph': None, 'indices': []},
             '1d': {'indices': [1, 2]},
             '2d': {'indices': {}}}
    source = ColumnDataSource(data=data, selected=selected)

    columns = [TableColumn(field="x", title="X")]

    data_table = DataTable(source=source, columns=columns)

    # Save the table and start the test
    save(data_table)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)
    screenshot.assert_is_valid()
Пример #52
0
def test_reset_triggers_range_callback(output_file_url, selenium):

    # Make plot and add a range callback that generates an alert
    plot = make_plot('reset')
    range1d = plot.select(dict(type=Range1d))[0]
    range1d.callback = CustomJS(code='alert("plot reset")')

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Tap the plot and test for alert
    reset_button = selenium.find_element_by_class_name('bk-tool-icon-reset')
    click_element_at_position(selenium, reset_button, 10, 10)
    alert = selenium.switch_to_alert()
    assert alert.text == 'plot reset'
Пример #53
0
def test_color_bar_with_scale_alpha(output_file_url, selenium, screenshot):
    plot = Plot(height=HEIGHT, width=WIDTH,
                x_range=Range1d(0,10), y_range=Range1d(0,10),
                outline_line_alpha=0.0, toolbar_location=None)

    bar_vertical_in_frame = create_vertical_color_bar_with_log_cmap()
    bar_vertical_in_frame.scale_alpha = 0.5

    plot.add_layout(bar_vertical_in_frame)

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Take screenshot
    screenshot.assert_is_valid()
Пример #54
0
def test_tap_with_callback_triggers_alert(output_file_url, selenium):

    # Make plot and add a taptool callback that generates an alert
    plot = make_plot('tap')
    tap = plot.select(dict(type=TapTool))[0]
    tap.callback = CustomJS(code='alert("tapped")')

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Tap the plot and test for alert
    canvas = selenium.find_element_by_tag_name('canvas')
    click_glyph_at_position(selenium, canvas, 250, 400)
    alert = selenium.switch_to_alert()
    assert alert.text == 'tapped'
Пример #55
0
def test_reset_triggers_factorrange_callback(output_file_url, selenium):
    x_range = FactorRange(factors=["a", "b", "c"])
    x_range.callback = CustomJS(code='alert("plot reset")')
    y_range = Range1d()

    # Make plot and add a range callback that generates an alert
    plot = make_plot(x_range, y_range, tools='reset')

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Tap the plot and test for alert
    reset_button = selenium.find_element_by_class_name('bk-tool-icon-reset')
    click_element_at_position(selenium, reset_button, 10, 10)
    alert = selenium.switch_to_alert()
    assert alert.text == 'plot reset'
def test_rect_rendering_with_log_axis(output_file_url, selenium, screenshot):

    plot = Plot(plot_height=400, plot_width=400,
       x_range=Range1d(0,30), y_range=Range1d(1,100),
       y_axis_type="log")

    x = [10, 20]
    y = [10, 20]

    source = ColumnDataSource(data=dict(x=[(x[0]+x[1])/2], y=[(y[0]+y[1])/2], width=[x[1]-x[0]], height=[y[1]-y[0]]))
    plot.add_glyph(source, Rect(x='x', y='y', width='width', height='height'))

    plot.add_layout(LogAxis(), "left")

    # Save the plot and start the test
    save(plot)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)
    screenshot.assert_is_valid()
Пример #57
0
def test_scale_width_resizes_plot_while_maintaining_aspect_ratio(output_file_url, selenium):

    # We want the aspect ratio of the initial plot to be maintained, but we
    # can't measure it perfectly so we test against bounds.
    aspect_ratio = 2
    plot_height = 400
    plot_width = 400 * aspect_ratio
    lower_bound = aspect_ratio * 0.95
    upper_bound = aspect_ratio * 1.05

    # In this test we tell selenium what to set the browser window to be
    # initially and then finally so we can test that the canvas has
    # scaled down by approximately the correct amount.
    initial_window_width = 1200
    final_window_width = 600

    # Make the plot with autoresize
    plot = make_sizing_mode_plot(plot_width, plot_height, sizing_mode='scale_width')
    save(plot)

    # Open the browser with the plot and resize the window to get an initial measure
    selenium.set_window_size(width=initial_window_width, height=600)
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)
    canvas = selenium.find_element_by_tag_name('canvas')
    wait_for_canvas_resize(canvas, selenium)

    initial_height = canvas.size['height']
    initial_width = canvas.size['width']
    initial_aspect_ratio = initial_width / initial_height
    assert initial_aspect_ratio > lower_bound
    assert initial_aspect_ratio < upper_bound

    # Now resize to a smaller window size and check again
    selenium.set_window_size(width=final_window_width, height=600)
    selenium.set_window_size(width=final_window_width, height=599)  # See note (1) below
    wait_for_canvas_resize(canvas, selenium)

    final_height = canvas.size['height']
    final_width = canvas.size['width']
    final_aspect_ratio = final_width / final_height
    assert final_aspect_ratio > lower_bound
    assert final_aspect_ratio < upper_bound
Пример #58
0
def _assert_autorange_prevents_panning_but_can_zoom(output_file_url, selenium):
    selenium.get(output_file_url)
    assert has_no_console_errors(selenium)

    # Zoom into plot so we can pan around a little
    zoom_plot(selenium)

    # Now the plot is zoomed in, try a little to the right
    pan_plot(selenium, pan_x=-50, pan_y=0)
    x_range_start = float(selenium.execute_script("""alert(window.get_x_range_start())"""))
    selenium.switch_to_alert().dismiss()
    assert x_range_start > 0.5

    # Now try panning far to left to check bounds
    pan_plot(selenium, pan_x=200, pan_y=0)
    x_range_start = float(selenium.execute_script("""alert(window.get_x_range_start())"""))
    selenium.switch_to_alert().dismiss()
    assert x_range_start > 0.4
    assert x_range_start < 0.5