Display hovertool for the uppermost glyph in bokeh? - python

I have a graph with several hundreds of glyphs on it, generated in bokeh. All the glyphs have a hovertool associated with them that shows a popup window with an image in it when moused over.
Some of the glyphs have 4-5 glyphs layered underneath them, and when someone mouses over them, all the hovertools are displayed.
Is it possible to only display the hovertool for the uppermost glyph?

As of Bokeh 1.3.4 there is no way to control the number of tooltips displayed without creating some sort of a custom extension. There is an open issue #9087 Provide max_tooltips property on HoverTool that is targeted for one of the next few releases.
But note: that work will just take a tooltip out of multiple to show. The draw order for a single glyph is not well-defined, it can change due to: spatial indexing, selections, "Level of Detail" mode being active, and other things. I don't know that there will ever be a reliable notion of "total z-order" such that e.g the "top" circle could be the one picked (and always be the same index). A more sophisticated selection manager could sort or condition on other CDS column values, etc. though, so you could potentially explicitly provide the order you intend.

Related

Latex (math mode) in Bokeh

all
Is there any chance I can use the math mode (latex code) in Bokeh? I checked all the Bokeh git issues (and possible options to solve) but nothing seems to work in my case :frowning:
Let’s say I have $\alpha_\beta$ (so alpha_beta) in my dataset (.csv) and I want to include it in a plot or hover - how would I do that? Sure I can use alpha symbol but how would I make beta be a subscript of alpha?
Thank you in advance!
Bokeh 2.4 adds support for LaTeX (and MathML) to some elements in Bokeh. Currently, you can use LaTeX on axis labels, tick labels, div widgets, and paragraph widgets. Unfortunately, LaTeX on hover labels is not yet supported, but LaTeX support for more elements should be added soon. For more information about the new math text feature and how to use them, see the Bokeh 2.4 release blogpost, the new blackbody radiation example, and the Bokeh user guide!

How to add Label/text in Bokeh that can be auto rescaled?

I learnt how to add text by using Label in Bokeh in this question.
However, I found that the text doesn't rescale as I zoom in and out.
The ideal behavior is something like Patches, which becomes larger as you zoom in.
How can I configure for this feature?
Related Questions
Selectively show text in Bokeh plot based on zoom level
As of Bokeh 2.3 scalable text is still an open issue:
https://github.com/bokeh/bokeh/issues/9407
There are some potential partial workarounds discussed there, but nothing that concretely works all the time. Depending on your use case, you could potentially use CustomJS callback on the plot ranges to update the text size that you care about in some way.

How to make Altair plots responsive

Can one make Altair plots fit the screen size, rather than have a pixel-defined width and height? I've read things about autosize "fit", but I am unsure about where to specify these.
While it is true that the vega-lite determines the size of the chart itself, it is possible to treat the chart (rendered as canvas) like an image.
I used an example from w3css which applied to my vega-light charts scales the charts accordingly. Basically it is then scaled proportionally according to the surrounding container.
Example HTML generated by vega-light:
<div id="visInteractiveYear" class="vega-embed">
<canvas width="1366" height="960" class="marks" style="width: 976px; height: 686px;"></canvas>
</div>
Here the CSS snippet, that basically overwrite width/height (style) of the canvas:
canvas.marks {
max-width: 100%!important;
height: auto!important;
}
Here a test without any scaling and its original size:
Here a test with scaling to fit within the surrounding box.
If you are using interactive charts, the scaling might be a problem. I guess that the click positions are not correctly translated (since canvas is scaled, but the logic of vega does not know about it), thus strange behaviour is the result. In my case, the selection has always an offset to the mouse cursor.
Also, the user has to zoom in to be able to read the chart, since it is proportionally scaled. Probably in most cases not the ideal user-friendly way to go.
Maybe a better option is to switch to another vega-light spec, which renders the chart for the specific display size, or to switch to a different representation (e.g., a standard list), which can then easily be read on smaller displays (adaptive design).
For complex charts, opening the chart in another browser tab, might be also be a good solution. The user knows about the new tab, the mobile browser has to show only one chart/image, so there is not much clutter to worry about. Thus, it is easy to navigate/scroll in the new tab, since it only contains the chart and maybe a back/close tab button.
There is no way to do this. The dimensions of Altair/Vega-Lite charts are pre-determined by the chart specification and data, and cannot be made to scale with the size of the browser window.
If you are using Altair 4.0 or greater you can use properties() and container:
import altair as alt
from vega_datasets import data
source = data.cars()
plot = alt.Chart(source).mark_circle(size=60).encode(
x='Horsepower',
y='Miles_per_Gallon',
color='Origin',
tooltip=['Name', 'Origin', 'Horsepower', 'Miles_per_Gallon']
).properties(
width='container',
height='container'
)
This will make it responsive, note that this is the size of each plot if you have multiple it doesn't work as you would expect but instead each plot will have the size of the parent container.

How does this Bokeh Column Data Source Work?

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.

How to create a user created textbox on top of matplotlib figure?

BackGround
I'm making this software right plot data as boxplots and scatter plots. To make the graph more informative and clear I wanted the user to be able to drag-create a textbox on top of the figure if they wanted to add notes. This way when people share the figure it can be explained through these notes.
Current Approach and Problem
I have used annotate function to create a textbox in the upper right corner of the screen to tell the user how many data points have been used, but there are of few problems with this approach.
This is the code I used to create a text box to tell the user how many data pts there are.
self.axes.text(.98, .98, 'Number of Data Points: {}'.format(len(self.cleanedY)),
verticalalignment='top', horizontalalignment='right',
transform=self.axes.transAxes,
color='black', fontsize=9.5)
Extensive input that would have to be asked of the user. This includes the position coordinates, the actual text box, type of alignment.
The only way I know how to collect this info would be to create a Qdialog window prompting for all these inputs, which would be too cumbersome.
User doesn't have much control over being able to freely position the textbox and would have to know exact decimals to position the text box on the figure.
This is incredibly inefficient and inflexible. I want a way for the user to EASILY create these notes on the plot figure.
TLDR: Is there any way to develop a simple drag and create textbox option on a plot figure?
I'm not sure if this is what your looking for, but i found this similar example online. It doesn't allow for user to create a textbox, but adds annotations to the figure and allows you to move them around.
here's the link
http://scipy-cookbook.readthedocs.io/items/Matplotlib_Drag_n_Drop_Text_Example.html

Categories