Problem description
Since bokeh 0.12.5 it is possible to use interactive legends to hide or mute glyphs via clicking on them in the legend box. This is a great feature especially for more complex plots.
However, when used in conjunction with the hover tool, hidden glyphs should not trigger the hover tool because the user is provided with a tooltip for glyphs which are not visible (due to muting via the interactive legend).
Here is minimal code example for clarification:
import numpy as np
from bokeh.plotting import figure, show, output_notebook
x = np.arange(0, 10, 1)
p = figure(tools=["hover"])
p.line(x, x, legend="Line 1")
p.line(x, x/2, legend="Line 2")
p.legend.click_policy = "hide"
show(p)
This is the resulting plot (without hiding):
This is the plot with Line 2 being hidden but having an active hover tooltip:
Question
Is there an option I'm currently missing to deactivate hover tooltips for hidden glyphs? If not, does anyone can think of a short workaround (perhaps employing CustomCS)?
Thanks!
As of bokeh 0.12.6, it is fixed. For more, see the issue in the github repo here.
Related
I am trying to get a better understanding about the column data source in Bokeh (for Python). I found this code, but I can't seem to find the documentation that explains some things I am looking for, For instance:
Where is the callback from the lasso_select tool? I want to see where the expected functionality is described.
How is the functionality of the lasso_select described in code? (What if I want to change it?)
What is happening to the column data source so that the circles outside the lasso-select region change appearance? (I want to know how I can use the column data source for more complex visualization than is shown by this demo. So I'd like to know what dictionary field is being manipulated, and how is it being manipulated. For example, is there a hidden "color" field or something like that, which isn't explicit in this code?)
What code causes the figure to be redrawn when a lasso_select action is made?
I have many more questions related to this and the CDSView, but I'll stop here for now.
from bokeh.io import output_file, show
from bokeh.layouts import gridplot
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure
output_file("brushing.html")
x = list(range(-20, 21))
y0 = [abs(xx) for xx in x]
y1 = [xx**2 for xx in x]
# create a column data source for the plots to share
source = ColumnDataSource(data=dict(x=x, y0=y0, y1=y1))
TOOLS = "box_select,lasso_select,help"
# create a new plot and add a renderer
left = figure(tools=TOOLS, plot_width=300, plot_height=300, title=None)
left.circle('x', 'y0', source=source)
# create another new plot and add a renderer
right = figure(tools=TOOLS, plot_width=300, plot_height=300, title=None)
right.circle('x', 'y1', source=source)
p = gridplot([[left, right]])
show(p)
This is related to my previous question, where the only answer was very narrow in explaining for that specific question. However, I am really interested in what's going on under the hood to give the results that are seen. It would help my understanding a lot more if I could know some of those details.
1) There is no callback. The tool is responsible for defining a selection geometry, and and then hit-testing baed on that geometry. The hit test results are store in a selection property of the data source. Glyph renderers draw glyphs based on the selection property of their data source. If two glyph renderers (even on different plots) share the same data source, they will both draw the same set of selected/nonselected as a result.
2) If you mean the appearance of the normal vs selected vs non-selected objects, how to configure that is described in the docs here:
https://docs.bokeh.org/en/latest/docs/user_guide/styling.html#selected-and-unselected-glyphs
There are also a few properties on the LassoTool object itself, that control, e.g. whether a selection should be made on every mousemove, or only on mouseup, and what the selection overlay looks like. All of these are recorded in the ReferenceGuide. If you are asking how to change the implementation, as with msot everything in Bokeh, the real work is not done in Python, it is done in the JavaScript library BokehJS. The implementation of the LassoTool is here:
https://github.com/bokeh/bokeh/blob/master/bokehjs/src/lib/models/tools/gestures/lasso_select_tool.ts
If you want something fundamentally different you would need to implement your own custom model, including its JavaScript component. There is an entire User's Guide section about building custom extensions:
https://docs.bokeh.org/en/latest/docs/user_guide/extensions.html
3) The Plot is configured with various Renderers, one of which can be a GlyphRenderer. The GlyphRenderer itself does not draw anything, but it configures various sub-glyphs that are used to draw in specific situations:
glyph draws "normal" versions of glyphs (i.e. when there is no selection on the data source)
selected_glyph draws "selected" versions of glyphs (i.e. the ones inside a lasso or box tool when a selection is active)
nonselected_glyph draws the "non-selected" versions of glyphs (i.e. the ones outside a lasso or box tool when a selection is active) By default the non selection glyph is just a copy of the "normal" glyph with the alpha value set very low.
hover_glyph draws the "hovered" versions of glyphs (i.e. when a hover tool has inspected them)
You configure the appearance in the different situation by configuring properties on the glyphs that are used in each situation. There are sensible defaults for them, but they can be updated as described in the first link of 2)
4) BokehJS has an internal signal/slots event system that is used (among other things) to request canvas redraws whenever various properties change.
so using the bare minimum code to produce a chart in plotly.py:
from plotly.offline import plot
from plotly.graph_objs import Scatter
plot([Scatter(x=[1, 2, 3, 4, 5], y=[3, 2, 1, 2, 3])])
produces a nice chart with a modebar on top of it. I would like to embed my chart in a website where the bar seems really intrusive. In plotly.js there's a really simple way to disable to modebar as shown here. The solution in plotly.js is merely giving additional parameter: Plotly.newPlot('myDiv', data, layout, {displayModeBar: false});
I know there's a way to save static image from plotly where the modebar is obviously disabled, but that would lose the interactive hover-actions on the plot itself, which are useful, whereas the bar that comes with it is not really that useful in my case. What I'm wondering is if there's a way to do remove the modebar in a similiar fashion to how plotly.js works?
One solution, I suppose would be to always go through the produced HTML-file and add every part of the hover bar to r.modeBarButtonsToRemove, which could turn troublesome in the long run.
I've been able to do it using the config key word argument, like this:
graph = py.plot(
figure,
output_type='div',
auto_open=False,
show_link=False,
config=dict(
displayModeBar=False
)
)
I am a little late here. But just a side note, this won't disable the functions of the top bar so when you hover it will still zoom and pan (which is extremely annoying on plots that are viewed from a mobile device). But making it a static plot isn't a good solution because I still want users on a computer to be able to hover over the points on the plot.
I solved this by changing two of the figure layout settings.
xaxis_fixedrange and yaxis_fixedrange need to be set to True if you want to disable zooming.
Is there any way at the moment to add constant tooltips to a bokeh line plot in python? I did not find anything about it in the documention.
I am looking for a way to allow adding the tooltip interactively ala matlab. However, doing so via the code at first is acceptable.
thanks.
Currently (as of 0.8.1) the line glyph does not support hit testing, so it does not support a hover tool, either. However, if it suffices to have a hover tooltip on just the "points" of the line, then several people have uses a second set of transparent markers located at the same points as a workaround. Something like:
line(x, y)
circle(x, y, size=8, alpha=0)
There is an open issue for adding line hit testing, it should hopefully been in one of the next few releases.
I upgraded from Python(x,y) 2.7.2.3 to 2.7.6.0 in Windows 7 (and was happy to see that I can finally type function_name? and see the docstring in the Object Inspector again) but now the plotting doesn't work as it used to.
Previously (Spyder 2.1.9, IPython 0.10.2, matplotlib 1.2.1), when I plotted this script, for instance, it would plot the subplots side-by-side in an interactive window:
Now (Spyder 2.2.5, IPython 1.2.0, Matplotlib 1.3.1) when I try to plot things, it does the subplots as tiny inline PNGs, which is a change in IPython:
So I went into options and found this:
which seems to say that I can get the old interactive plots back, with the 4 subplots displayed side-by-side, but when I switch to "Automatic", and try to plot something, it does nothing. No plots at all.
If I switch this drop-down to Qt, or uncheck "Activate support", it only plots the first subplot, or part of it, and then stops:
How do I get the old behavior of 4 side-by-side subplots in a single figure that I can interact with?
Change the backend to automatic:
Tools > preferences > IPython console > Graphics > Graphics backend > Backend: Automatic
Then close and open Spyder.
You can quickly control this by typing built-in magic commands in Spyder's IPython console, which I find faster than picking these from the preferences menu. Changes take immediate effect, without needing to restart Spyder or the kernel.
To switch to "automatic" (i.e. interactive) plots, type:
%matplotlib auto
then if you want to switch back to "inline", type this:
%matplotlib inline
(Note: these commands don't work in non-IPython consoles)
See more background on this topic: Purpose of "%matplotlib inline"
After applying : Tools > preferences > Graphics > Backend > Automatic Just restart the kernel
And you will get Interactive Plot.
As said in the comments, the problem lies in your script. Actually, there are 2 problems:
There is a matplotlib error, I guess that you're passing an argument as None somewhere. Maybe due to the defaultdict ?
You call show() after each subplot. show() should be called once at the end of your script. The alternative is to use interactive mode, look for ion in matplotlib's documentation.
This is actually pretty easy to fix and doesn't take any coding:
1.Click on the Plots tab above the console.
2.Then at the top right corner of the plots screen click on the options button.
3.Lastly uncheck the "Mute inline plotting" button
Now re-run your script and your graphs should show up in the console.
For most mathematical coding, I use this website and their services as they offer examples for every subject and their support is super helpful:
https://labdeck.com/application-examples-screenshots/
If your want you graph to change by a variable amount then the code you want to use is
import matplotlib.pyplot as plt
import time
vec1=[1, 2, 3, 4, 5]
vec2py=[10, 12, 9, 11, 13]
plt.show()
axes = plt.gca()
axes.set_xlim(0, 6)
axes.set_ylim(5, 50)
plt.xlabel('x - axis')
plt.ylabel('y - axis')
plt.title('Example 1')
plt.grid()
line,= axes.plot(vec1,vec2py,color='red',lw=1)
for x in range(0,10):
vec2py = [x + 2 for x in vec2py]
line.set_ydata(vec2py)
plt.draw()
plt.pause(1e-17)
time.sleep(0.5)
plt.show()
You will have to change x for how many iterations of the graph you want and how long you want it to run for and also the +2 in the vec2py line for what variable amount you want to change it by. Naturally the code is a template and you can make any aesthetical changes. This code file is found under displaying dynamic graphs which is under python programming in the link above.
If you want to display a constant rely of information from a source, I'm not to sure how to do that but the website mention before does have an example, however it isn't in python but in a simplified form of C++.If you do want to see it then the link is https://labdeck.com/examples/dsp-ecg-processing/ecg-9-leads-graphs.pdf?01a96f&01a96f and its under ECG 9 Leads graphs in ECG on the link at the start.
The graph can be shown as in a document or independently from the document.
PS this is for people who have the same question but not necessarily the same scenario as I think this will help more.
I upgraded from Python(x,y) 2.7.2.3 to 2.7.6.0 in Windows 7 (and was happy to see that I can finally type function_name? and see the docstring in the Object Inspector again) but now the plotting doesn't work as it used to.
Previously (Spyder 2.1.9, IPython 0.10.2, matplotlib 1.2.1), when I plotted this script, for instance, it would plot the subplots side-by-side in an interactive window:
Now (Spyder 2.2.5, IPython 1.2.0, Matplotlib 1.3.1) when I try to plot things, it does the subplots as tiny inline PNGs, which is a change in IPython:
So I went into options and found this:
which seems to say that I can get the old interactive plots back, with the 4 subplots displayed side-by-side, but when I switch to "Automatic", and try to plot something, it does nothing. No plots at all.
If I switch this drop-down to Qt, or uncheck "Activate support", it only plots the first subplot, or part of it, and then stops:
How do I get the old behavior of 4 side-by-side subplots in a single figure that I can interact with?
Change the backend to automatic:
Tools > preferences > IPython console > Graphics > Graphics backend > Backend: Automatic
Then close and open Spyder.
You can quickly control this by typing built-in magic commands in Spyder's IPython console, which I find faster than picking these from the preferences menu. Changes take immediate effect, without needing to restart Spyder or the kernel.
To switch to "automatic" (i.e. interactive) plots, type:
%matplotlib auto
then if you want to switch back to "inline", type this:
%matplotlib inline
(Note: these commands don't work in non-IPython consoles)
See more background on this topic: Purpose of "%matplotlib inline"
After applying : Tools > preferences > Graphics > Backend > Automatic Just restart the kernel
And you will get Interactive Plot.
As said in the comments, the problem lies in your script. Actually, there are 2 problems:
There is a matplotlib error, I guess that you're passing an argument as None somewhere. Maybe due to the defaultdict ?
You call show() after each subplot. show() should be called once at the end of your script. The alternative is to use interactive mode, look for ion in matplotlib's documentation.
This is actually pretty easy to fix and doesn't take any coding:
1.Click on the Plots tab above the console.
2.Then at the top right corner of the plots screen click on the options button.
3.Lastly uncheck the "Mute inline plotting" button
Now re-run your script and your graphs should show up in the console.
For most mathematical coding, I use this website and their services as they offer examples for every subject and their support is super helpful:
https://labdeck.com/application-examples-screenshots/
If your want you graph to change by a variable amount then the code you want to use is
import matplotlib.pyplot as plt
import time
vec1=[1, 2, 3, 4, 5]
vec2py=[10, 12, 9, 11, 13]
plt.show()
axes = plt.gca()
axes.set_xlim(0, 6)
axes.set_ylim(5, 50)
plt.xlabel('x - axis')
plt.ylabel('y - axis')
plt.title('Example 1')
plt.grid()
line,= axes.plot(vec1,vec2py,color='red',lw=1)
for x in range(0,10):
vec2py = [x + 2 for x in vec2py]
line.set_ydata(vec2py)
plt.draw()
plt.pause(1e-17)
time.sleep(0.5)
plt.show()
You will have to change x for how many iterations of the graph you want and how long you want it to run for and also the +2 in the vec2py line for what variable amount you want to change it by. Naturally the code is a template and you can make any aesthetical changes. This code file is found under displaying dynamic graphs which is under python programming in the link above.
If you want to display a constant rely of information from a source, I'm not to sure how to do that but the website mention before does have an example, however it isn't in python but in a simplified form of C++.If you do want to see it then the link is https://labdeck.com/examples/dsp-ecg-processing/ecg-9-leads-graphs.pdf?01a96f&01a96f and its under ECG 9 Leads graphs in ECG on the link at the start.
The graph can be shown as in a document or independently from the document.
PS this is for people who have the same question but not necessarily the same scenario as I think this will help more.