I am a new python learner and am trying to make a plot with bokeh. I want to use the hover tool and it is working when I scroll over the dots. However, the X and Y values are showing ??? instead of the actual values. I'm not quite sure what I'm doing incorrectly because the hovertool itself is working, but the values are not displaying.
from bokeh.plotting import figure`
from bokeh.io import show, output_notebook
get_provider(Vendors.CARTODBPOSITRON)
from bokeh.models import ColumnDataSource, HoverTool
# Create a blank figure with labels
p = figure(plot_width = 600, plot_height = 600,
title = 'Example Glyphs',
x_axis_label = 'X', y_axis_label = 'Y')
hover = HoverTool(tooltips=[
("X", "#X "),
("Y","#Y")])
p = figure(x_axis_type="mercator",
y_axis_type="mercator",
tools=[hover, 'wheel_zoom','save'])
p.add_tile(CARTODBPOSITRON)
# Example data
circles_x = [1, 3, 4, 5, 8]
circles_y = [8, 7, 3, 1, 10]
circles_x = [9, 12, 4, 3, 15]
circles_y = [8, 4, 11, 6, 10]
# Add squares glyph
p.circle(squares_x, squares_y, size = 12, color = 'navy', alpha = 0.6)
# Add circle glyph
p.circle(circles_x, circles_y, size = 12, color = 'red')
# Set to output the plot in the notebook
output_notebook()
# Show the plot
show(p)
If you aren't using an explicit ColumnDataSource (which would allow you to use and refer to whatever column names you want), then you must refer to the default column names Bokeh uses. In this case, for circle, the default column names are "x" and "y" (lower case, not upper case as you have above). So:
hover = HoverTool(tooltips=[
("X", "#x"),
("Y", "#y"),
])
Related
I am trying to get a graph that has all of the x-axis values filled but starts with y-axis values that are NaN. It appears that the graph will start at the first real y-axis value. Here is the example:
from bokeh.plotting import figure, output_file, show
output_file("line.html")
p = figure(plot_width=400, plot_height=400)
# add a line renderer with a NaN
n = float('nan')
p.line(
[1, 2, 3, 4, 5], # x-axis
[n, n, 7, 2, 4], # y-axis
line_width=2
)
show(p)
This is the result:
As you can see the first 2 elements of the x-axis array aren't shown.
I was hoping to find a way to force bokeh graph to show all values or a workaround to the same effect.
You could explicitly set the start (or end) of the plot's x (or y) axis. Like so:
from bokeh.plotting import figure, output_file, show
output_file("line.html")
p = figure(plot_width=400, plot_height=400)
# add a line renderer with a NaN
n = float('nan')
x_values = [1, 2, 3, 4, 5] # x-axis
y_values = [n, n, 7, 2, 4] # y-axis
p.line(x=x_values, y=y_values, line_width=2)
# of course in real life it'd make sense to do max and min of x and y,
# but this is all we need for your specific example.
p.x_range.start = min(x_values)
show(p)
I saw this example
from bokeh.models import ColumnDataSource, OpenURL, TapTool
from bokeh.plotting import figure, output_file, show
output_file("openurl.html")
p = figure(plot_width=400, plot_height=400,
tools="tap", title="Click the Dots")
source = ColumnDataSource(data=dict(
x=[1, 2, 3, 4, 5],
y=[2, 5, 8, 2, 7],
color=["navy", "orange", "olive", "firebrick", "gold"]
))
p.circle('x', 'y', color='color', size=20, source=source)
# use the "color" column of the CDS to complete the URL
# e.g. if the glyph at index 10 is selected, then #color
# will be replaced with source.data['color'][10]
url = "http://www.colors.commutercreative.com/#color/"
taptool = p.select(type=TapTool)
taptool.callback = OpenURL(url=url)
show(p)
I would like to do something similar, instead of opening the url, I would like to show some text on the right when i click on the circle related to that circle. And the text should change when I click on another circle.
I also saw this: https://docs.bokeh.org/en/latest/docs/user_guide/interaction/callbacks.html#customjs-for-user-interaction-events but I couldn't change the mouse prints with some text based on the circle.
Thank you.
use CustomJS instead of OpenUrl
from bokeh.models import CustomJS
taptool.callback = CustomJS(code="""
var ind = cb_data.index['1d'].indices[0];
var color = cb_obj.source.data['color'][ind];
$('#div_id').text(color);
""")
more explanations see here JavaScript callback to get selected glyph index in Bokeh
I am trying to make a bokeh serve plot with a CheckButtonGroup. I manage to update my source.data but the plot does not get updated. What am I doing wrong?
In reality, I import the dataset from my computer, but for now I will create an example pandas dataframe. I want to select the 'x' column (as x-axis variable) and one or more of the other columns (as y-axis variables).
import pandas as pd
from bokeh.io import curdoc
from bokeh.plotting import figure
from bokeh.layouts import row, widgetbox
from bokeh.models.widgets import CheckboxButtonGroup
from bokeh.models import ColumnDataSource
dataset = pd.DataFrame(columns=['x','y1','y2','y3'])
dataset['x'] = [1, 2, 3, 4]
dataset['y1'] = [10, 20, 30, 40]
dataset['y2'] = [11, 21, 31, 41]
dataset['y3'] = [12, 22, 32, 43]
pos_cols = ['y1', 'y2', 'y3'] # possible column names
col_list = ['y1', 'y2'] # default columns in plotted data
use_data = dataset[col_list]
use_data['x'] = dataset.loc[:, 'x']
source = ColumnDataSource(use_data)
p = figure(
tools="pan,box_zoom,wheel_zoom,reset,save",
x_axis_label='xtitle', y_axis_label='ytitle',
title="Simulations"
)
# make default plot with the two columns
for column in col_list:
p.line('x', column, source=source)
check = CheckboxButtonGroup(labels=["y1", "y2", "y3"], active=[0, 1]) # A check box for every column
def update_lines(new):
col_list = [pos_cols[i] for i in new]
use_data = dataset[col_list]
use_data['x'] = dataset.loc[:, 'x']
source.data = source.from_df(use_data)
print(source.data) # source.data is correctly updated, but does not seem to trigger a new plot
check.on_click(update_lines)
doc = curdoc()
doc.add_root(row(check, p, width=800))
doc.title = "Simulations"
I save the code as try.py and run it from the windows prompt with bokeh serve try.py. The plot is visible at http://localhost:5006
The problem is that you are creating glyphs for columns like 'y3' up front, but not actually sending any column 'y3' to start. Bokeh does not like that (you can see error messages about trying to access non-existent columns in the browser JS console)
A better approach, that also does not unnecessarily re-send all the data, might be to just toggle the .visible attribute of the glyph renderers. Here is a minimal example (that starts with all lines visible, but you could change that):
import pandas as pd
from bokeh.io import curdoc
from bokeh.plotting import figure
from bokeh.layouts import row
from bokeh.models import CheckboxButtonGroup, ColumnDataSource
dataset = pd.DataFrame(columns=['x','y1','y2','y3'])
dataset['x'] = [1, 2, 3, 4]
dataset['y1'] = [10, 20, 30, 40]
dataset['y2'] = [11, 21, 31, 41]
dataset['y3'] = [12, 22, 32, 43]
source = ColumnDataSource(data=dataset)
p = figure( )
lines = []
for column in ['y1', 'y2', 'y3']:
lines.append(p.line('x', column, source=source))
check = CheckboxButtonGroup(labels=["y1", "y2", "y3"], active=[0, 1, 2])
def update_lines(new):
for i in [0, 1, 2]:
if i in new:
lines[i].visible = True
else:
lines[i].visible = False
check.on_click(update_lines)
doc = curdoc()
doc.add_root(row(check, p, width=800))
Alternatively, if you are just looking to be able to hide or mute lines, an much easier way would be to use Bokeh's built in Interactive Legends:
http://docs.bokeh.org/en/latest/docs/user_guide/interaction/legends.html#userguide-interaction-legends
I want to have a scatter plot and a (base)line on the same figure. And I want to use HoverTool only on the circles of scatter but not on the line. Is it possible?
With the code below I get tooltips with index: 0 and (x, y): (???, ???) when I hover on the line (any part of the line). But the index: 0 data in source is totally different ((x, y): (1, 2))...
df = pd.DataFrame({'a':[1, 3, 6, 9], 'b':[2, 3, 5, 8]})
from bokeh.models import HoverTool
import bokeh.plotting as bplt
TOOLS = ['box_zoom', 'box_select', 'wheel_zoom', 'reset', 'pan', 'resize', 'save']
source = bplt.ColumnDataSource(data=df)
hover = HoverTool(tooltips=[("index", "$index"), ("(x, y)", "(#a, #b)")])
p = bplt.figure(plot_width=600, plot_height=600, tools=TOOLS+[hover],
title="My sample bokeh plot", webgl=True)
p.circle('a', 'b', size=10, source=source)
p.line([0, 10], [0, 10], color='red')
bplt.save(p, 'c:/_teszt.html')
Thank you!!
To limit which renderers you want the HoverTool is active on (by default it's active on all) you can either set a name attr on your glyphs, then specify which names you want your HoverTool to be active on:
p.circle('a', 'b', size=10, name='circle', source=source)
hover = HoverTool(names=['circle'])
docs:
http://docs.bokeh.org/en/latest/docs/reference/models/tools.html#bokeh.models.tools.HoverTool.names
or you can add the renderers to the HoverTool.
circle = p.circle('a', 'b', size=10, source=source)
hover = HoverTool(renderers=['circle'])
docs:
http://docs.bokeh.org/en/latest/docs/reference/models/tools.html#bokeh.models.tools.HoverTool.renderers
I would like to click-and-drag the scatter points the points of a bokeh scatter plot. Any ideas how to do this?
(edit: this is an example of what I'd like to do)
For an example of a scatter, the code below generates the scatter plot chart found half-way through this page.
from bokeh.plotting import figure, output_file, show
# create a Figure object
p = figure(width=300, height=300, tools="pan,reset,save")
# add a Circle renderer to this figure
p.circle([1, 2.5, 3, 2], [2, 3, 1, 1.5], radius=0.3, alpha=0.5)
# specify how to output the plot(s)
output_file("foo.html")
# display the figure
show(p)
Multi-gesture edit tools are only a recent addition, landing in version 0.12.14. You can find much more information in the Edit Tools section of the User's Guide.
Specifically to be able to move points as described in the OP, use the PointDrawTool:
Here is a complete example you can run that also has a data table showing the updated coordinates of the glyphs as they are moved (you will need to activate the tool in the toolbar first, it is off by default):
from bokeh.plotting import figure, output_file, show, Column
from bokeh.models import DataTable, TableColumn, PointDrawTool, ColumnDataSource
output_file("tools_point_draw.html")
p = figure(x_range=(0, 10), y_range=(0, 10), tools=[],
title='Point Draw Tool')
p.background_fill_color = 'lightgrey'
source = ColumnDataSource({
'x': [1, 5, 9], 'y': [1, 5, 9], 'color': ['red', 'green', 'yellow']
})
renderer = p.scatter(x='x', y='y', source=source, color='color', size=10)
columns = [TableColumn(field="x", title="x"),
TableColumn(field="y", title="y"),
TableColumn(field='color', title='color')]
table = DataTable(source=source, columns=columns, editable=True, height=200)
draw_tool = PointDrawTool(renderers=[renderer], empty_value='black')
p.add_tools(draw_tool)
p.toolbar.active_tap = draw_tool
show(Column(p, table))