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))
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 plot with circles on it and I want users to be able to select circles and then I want to do some stuff on python side depending on the circle.
I have tried JS callbacks but I get the error:
WARNING:bokeh.embed.util: You are generating standalone HTML/JS
output, but trying to use real Python callbacks (i.e. with on_change
or on_event). This combination cannot work. Only JavaScript callbacks
may be used with standalone output. For more information on JavaScript
callbacks with Bokeh, see:
http://docs.bokeh.org/en/latest/docs/user_guide/interaction/callbacks.html
Alternatively, to use real Python callbacks, a Bokeh server
application may be used. For more information on building and running
Bokeh applications, see:
http://docs.bokeh.org/en/latest/docs/user_guide/server.html
Here's some code if you want to try to do it.
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)```
I didnt quite understand your question, but you can use hover tool to add interaction, or LabelSet to display your x/y along with the dots.
from bokeh.plotting import figure
from bokeh.io import show, output_notebook
output_notebook()
p = figure(plot_width=400, plot_height=400, tools="tap, reset, hover", title="Click
the Dots", tooltips = [('x', '#x'),('y','#y')])
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)
show(p)
I have the following problem when using bokeh's TapTool and DataTable together:
As soon as one dot is clicked (TapTool used), selections on the DataTable do no longer get represented in the plot anymore.
Here is the minimal example for a Jupyter Notebook:
from bokeh.plotting import show, output_notebook, figure
from bokeh.models import ColumnDataSource, OpenURL, TapTool
from bokeh.layouts import widgetbox, column
from bokeh.models.widgets import DataTable, TableColumn
source = ColumnDataSource(dict(
x=[1, 2, 3, 4, 5],
y=[6, 7, 2, 4, 5],
url=["http://www.stackoverflow.com"]*5))
p = figure(plot_width=400,
plot_height=400,
tools="tap,reset",
)
p.circle(source=source,
x="x",
y="y",
size=20,
color="navy",
alpha=0.5)
columns = [
TableColumn(field="x", title="X-Value"),
TableColumn(field="y", title="Y-Value"),
TableColumn(field="url", title="URL")
]
data_table = DataTable(source=source, columns=columns,
width=400, height=400)
url = "#url"
taptool = p.select(type=TapTool)
taptool.callback = OpenURL(url=url)
output_notebook()
show(column(p, widgetbox(data_table)))
Expected behaviour: Selections from the DataTable get represented in the plot like before clicking one dot.
Thank you all in advance.
Problem solved. This was an issue in bokeh 0.13
With anaconda I couldn't update to 1.0.1, so I created a new environment, where bokeh can be 1.0.1 an the problem no longer exists.
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 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