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
Related
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"),
])
I have a stacked vbar chart in Bokeh, a simplified version of which can be reproduced with:
from bokeh.plotting import figure
from bokeh.io import show
months = ['JAN', 'FEB', 'MAR']
categories = ["cat1", "cat2", "cat3"]
data = {"month" : months,
"cat1" : [1, 4, 12],
"cat2" : [2, 5, 3],
"cat3" : [5, 6, 1]}
colors = ["#c9d9d3", "#718dbf", "#e84d60"]
p = figure(x_range=months, plot_height=250, title="Categories by month",
toolbar_location=None)
p.vbar_stack(categories, x='month', width=0.9, color=colors, source=data)
show(p)
I want to add a legend to the chart, but my real chart has a lot of categories in the stacks and therefore the legend would be very large, so I want it to be outside the plot area to the right.
There's a SO answer here which explains how to add a legend outside of the plot area, but in the example given each glyph rendered is assigned to a variable which is then labelled and added to a Legend object. I understand how to do that, but I believe the vbar_stack method creates mutliple glyphs in a single call, so I don't know how to label these and add them to a separate Legend object to place outside the chart area?
Alternatively, is there a simpler way to use the legend argument when calling vbar_stack and then locate the legend outside the chart area?
Any help much appreciated.
For anyone interested, have now fixed this using simple indexing of the vbar_stack glyphs. Solution below:
from bokeh.plotting import figure
from bokeh.io import show
from bokeh.models import Legend
months = ['JAN', 'FEB', 'MAR']
categories = ["cat1", "cat2", "cat3"]
data = {"month" : months,
"cat1" : [1, 4, 12],
"cat2" : [2, 5, 3],
"cat3" : [5, 6, 1]}
colors = ["#c9d9d3", "#718dbf", "#e84d60"]
p = figure(x_range=months, plot_height=250, title="Categories by month",
toolbar_location=None)
v = p.vbar_stack(categories, x='month', width=0.9, color=colors, source=data)
legend = Legend(items=[
("cat1", [v[0]]),
("cat2", [v[1]]),
("cat3", [v[2]]),
], location=(0, -30))
p.add_layout(legend, 'right')
show(p)
Thanks Toby Petty for your answer.
I have slightly improved your code so that it automatically graps the categories from the source data and assigns colors. I thought this might be handy as the categories are often not explicitly stored in a variable and have to be taken from the data.
from bokeh.plotting import figure
from bokeh.io import show
from bokeh.models import Legend
from bokeh.palettes import brewer
months = ['JAN', 'FEB', 'MAR']
data = {"month" : months,
"cat1" : [1, 4, 12],
"cat2" : [2, 5, 3],
"cat3" : [5, 6, 1],
"cat4" : [8, 2, 1],
"cat5" : [1, 1, 3]}
categories = list(data.keys())
categories.remove('month')
colors = brewer['YlGnBu'][len(categories)]
p = figure(x_range=months, plot_height=250, title="Categories by month",
toolbar_location=None)
v = p.vbar_stack(categories, x='month', width=0.9, color=colors, source=data)
legend = Legend(items=[(x, [v[i]]) for i, x in enumerate(categories)], location=(0, -30))
p.add_layout(legend, 'right')
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'm experimenting with Bokeh and running into a frustrating problem with the hovertool. It lists fill color as one of the basic tooltips covered.
http://docs.bokeh.org/en/latest/docs/user_guide/tools.html#hover-tool
I tried a test and the color will not appear on the hovertool. It doesn't even give me the "???" it usually does when you give it a input it doesn't understand, it just ignores it completely. Anyone have a clue as to why it wouldn't display one of the basic tooltips?
from bokeh.plotting import figure, output_file, show, ColumnDataSource
from bokeh.models import HoverTool
output_file("toolbar.html")
source = ColumnDataSource(
data=dict(
x=[1, 2, 3, 4, 5],
y=[2, 5, 8, 2, 7],
desc=['A', 'b', 'C', 'd', 'E'],
)
)
hover = HoverTool(
tooltips=[
("fill color", "$color[hex, swatch]:fill_color"),
("index", "$index"),
("(x,y)", "($x, $y)"),
("desc", "#desc"),
]
)
p = figure(plot_width=400, plot_height=400, tools=[hover],
title="Mouse over the dots")
p.circle('x', 'y', size=20, source=source, fill_color="black")
show(p)
Hover tooltips can only inspect values from actual columns in a column data source. Since you have given a fixed value, i.e. fill_color="black" there is no column to inspect. Additionally, the special hover field $color with hex only understands hex color strings.
Here is your code modified to work:
from bokeh.plotting import figure, output_file, show, ColumnDataSource
from bokeh.models import HoverTool
output_file("toolbar.html")
source = ColumnDataSource(
data=dict(
x=[1, 2, 3, 4, 5],
y=[2, 5, 8, 2, 7],
desc=['A', 'b', 'C', 'd', 'E'],
fill_color=['#88ffaa', '#aa88ff', '#ff88aa', '#2288aa', '#6688aa']
)
)
hover = HoverTool(
tooltips=[
("index", "$index"),
("fill color", "$color[hex, swatch]:fill_color"),
("(x,y)", "($x, $y)"),
("desc", "#desc"),
]
)
p = figure(plot_width=400, plot_height=400, tools=[hover],
title="Mouse over the dots")
p.circle('x', 'y', size=20, source=source, fill_color="fill_color")
show(p)
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))