I'm using Bokeh line glyphs with nan values to create an image with many line segments.
I would like to selectively turn some of these glyphs off. What is the best way to accomplish this?
My first attempt is to have a visible column, and use a CDSView to turn each line segment on or off. However this has no effect, I suspect because bokeh identifies all of these line segments as a single glyph. Is there a way to use CDSView to turn off various parts of a line glyph? Is there another glyph that I should be looking at instead?
The easiest approach would be to use a multi_line glyph, which lets you plot a lot of individual line segments declared as separate arrays. Once you've done that you could control the visibility of each line segment by declaring a separate alpha column. Here is a minimal example:
from bokeh.plotting import figure, show
from bokeh.models import ColumnDataSource
p = figure()
source = ColumnDataSource(data={
'xs': [[1, 2, 3], [1, 2, 3]],
'ys': [[1, 2, 3], [2, 3, 4]],
'alpha': [0, 1]
})
p.multi_line(xs='xs', ys='ys', line_alpha='alpha', source=source)
show(p)
Related
I would like to display the hover information on a stocks plot based on a given x-value instead of the current mouse position.
EDIT: the x-value is set with a slider.
EDIT2:
I am running a folder app and use slider "on change" events. I want to pass the slider value to the plot. There are several plots and the slider just serves the function of highlighting a position simultaneously in all plots. Here is the relevant code:
slider.on_change('value', update_plots)
def update_plots(attr, old, new):
# some code involving 'slider.value'
# e.g. plot.set_hover_by_x_value(slider.value)
EDIT3:
A minimal example would be a single line plot and a slider that is used to highlight a point on the line:
p = figure(plot_width=400, plot_height=400)
p.line([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], line_width=2)
slider = Slider(start=0, end=5, value=0, step=1, title='x-value')
slider.on_change('value', update_plots)
def update_plots(attr, old, new):
# magic code to highlight the point "slider.value" in "p"
As of Bokeh 1.1 there is no programmatic means to create hover tooltips. They are currently tied to explicit, actual UI interactions (e.g. a mouse moving and hitting a scatter point).
As an alternative, you could use a Label annotation to display information at a given location instead.
There are two kinds of tooltips in Bokeh:
#: Associated with columns in a ColumnDataSource object
$: Special fields such as coordinates of the mouse
In this case you should use #column_with_x_values in your tooltip list for your hovertool to show the given x-values.
More information on the hovertool and examples can be found on this page.
In Bokeh, what are 'screen units'?
The web isn't forthright on what these creatures are and I've had no luck gleaning their meaning from the (0.9.3) source code
The Bokeh source uses them in its examples, such as this from bokeh/_glyph_functions.py for 'rect':
from bokeh.plotting import figure, output_file, show
plot = figure(width=300, height=300)
plot.rect(x=[1, 2, 3], y=[1, 2, 3], width=10, height=20, color="#CAB2D6",
width_units="screen", height_units="screen")
show(plot)
but I don't see them defined anywhere. What other options would 'width_units' support?
Bokeh lets users set renderer locations either by screen units (related to the pixel distance from the origin of the plot) or data units (which uses the mapper that is used to calculate the plot ranges based on the input data)
This helps in cases like adding box annotations, where sometimes you want the box to be linked to screen (perhaps always in the middle of the screen) or linked to data values (having a box at x=10)
The docs:
https://github.com/bokeh/bokeh/blob/master/bokeh/enums.py#L46
I create a row of plots in a graphic device with the par() command and run the first 2 plots:
par(mfrow = c(1, 4))
hist(mydata)
boxplot(y ~ x)
Now let's say the boxplot is wrong and I want to replace it with a new one. By default the next plot goes to the left side of the previous one (or one row below, first column, in case of a multiple rows layout), leaving the previous plot unchanged.
Is there a way to specify the location of the next plot in the multiplot grid area?
To specify the location of the next plot in the multiplot grid area, I prefer to use the function layout.
The layout function provides an alternative to the mfrow and mfcol settings.
For example the equivalent of par(mfrow = c(1, 4)) is :
layout(matrix(c(1, 3, 2, 4), byrow=TRUE, ncol=4))
or
layout(matrix(c(1, 2, 3, 4), byrow=TRUE, ncol=4))
The function layout.show() may be helpful for visualizing the figure regions
that are created. The following code creates a figure visualizing the layout
created in the previous example:
layout.show(4)
The base graphics model is ink-on-paper and does not allow revisions. The lattice and ggplot models are based on lists that can be modified. You can "go back" an add items with lines, points and as pointed out you can change the focus to a particular panel, but to remove or replace stuff .... not possible. Re-running the code shouldn't be a big problem, should it? Pixels are very cheap.
You can specify the next frame to plot to useing the mfg argument to par. See ?par for details. So a command like:
par(mfg=c(1,2))
Will mean that the next high level plot will go to the plot in the 1st row 2nd column. This can be used to plot in your own custom order. However, using layout for this is probably easier better in most cases.
When you use this to specify a frame to plot in R assumes that the frame is ready to be plotted in, it will not remove anything already there, so if there is an existing plot there it will be plotted over and you will likely see both plots and it won't look pretty.
You can draw a rectangle over the top of an existing plot to give yourself a blank frame to plot in using code like:
par(xpd=NA)
rect( grconvertX(0, from='nfc'), grconvertY(0,from='nfc'),
grconvertX(1,from='nfc'), grconvertY(1, from='nfc'),
col='white',border='white')
This works OK for looking at on the screen, but you need to be careful with this if exporting or printing, in some cases the printer or interpreter of the graphics file will interpret the white rectangle as "do nothing" and you will again see both plots.
In general it is best to do plots that take more than a line or 2 of code in a script window so that if you want to change something you can edit the script and just recreate the whole plot from scratch rather than relying on tricks like this.
How can I make a 3D plot without showing the axes?
When plotting a 3d plot, Matplotlib not only draws the x, y, and z axes, it draws light gray grids on the x-y, y-z, and x-z planes. I would like to draw a "free-floating" 3D plot, with none of these elements.
Stuff I've tried:
# Doesn't work; this hides the plot, not the axes
my_3d_axes.set_visible(False)
# Doesn't do anything. Also, there's no get_zaxis() function.
my_3d_axes.get_xaxis().set_visible(False)
my_3d_axes.get_yaxis().set_visible(False)
Ben Root provided a patch that fixes this for 1.0.1. It can be found as an attachment to the last email of this thread. To quote Ben:
Ok, looks like the hiding of the 3d axes was a feature added after the v1.0 release (but before I started working on mplot3d). This patch should enable the basic feature without interfering with existing functions. To hide the axes, you would have to set the private member "_axis3don" to False, like so:
ax = plt.gca(projection='3d')
ax._axis3don = False
If you do it this way, then you will get what you want now, and your code will still be compatible with mplot3d when you upgrade (although the preferred method would be to call set_axis_on() or set_axis_off()).
I hope that helps!
Ben Root
ax.set_axis_off()
Just to provide a concrete and direct example of what was mentioned at https://stackoverflow.com/a/7363931/895245
#!/usr/bin/env python3
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
import mpl_toolkits.mplot3d.art3d as art3d
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.set_axis_off()
# Draw a circle on the x=0 'wall'
p = Circle((0, 0), 1, fill=False)
ax.add_patch(p)
art3d.pathpatch_2d_to_3d(p, zdir="x")
p = Circle((0, 0), 1, fill=False)
ax.add_patch(p)
art3d.pathpatch_2d_to_3d(p, zdir="z")
ax.set_xlim(-1.2, 1.2)
ax.set_ylim(-1.2, 1.2)
ax.set_zlim(-1.2, 1.2)
plt.savefig('main.png', format='png', bbox_inches='tight')
Output:
Without ax.set_axis_off() it would look like:
You will notice however that this produces an excessively large whitespace margin around the figure as it simply hides the axes but does not change the viewbox. I tried bbox_inches='tight' and it did not help as it does in 2D. How to solve that at: Remove white spaces in Axes3d (matplotlib)
Tested on matplotlib==3.2.2.
I'm trying to plot a log-log graph that shows logarithmically spaced grid lines at all of the ticks that you see along the bottom and left hand side of the plot. I've been able to show some gridlines by using matplotlib.pyplot.grid(True), but this is only showing grid lines for me at power of 10 intervals. So as an example, here is what I'm currently getting:
I'd really like something with grid lines looking more like this, where the gridlines aren't all evenly spaced:
How would I go about achieving this in Matplotlib?
Basically, you just need to put in the parameter which="both" in the grid command so that it becomes:
matplotlib.pyplot.grid(True, which="both")
Other options for which are 'minor' and 'major' which are the major ticks (which are shown in your graph) and the minor ticks which you are missing. If you want solid lines then you can use ls="-" as a parameter to grid() as well.
Here is an example for kicks:
import numpy as np
from matplotlib import pyplot as plt
x = np.arange(0, 100, .5)
y = 2 * x**3
plt.loglog(x, y)
plt.grid(True, which="both", ls="-")
plt.show()
which generates:
More details on the Matplotlib Docs
As #Bryce says, in older version of matplotlib correct kwarg is which=majorminor. I think that solid lines with a lighter color can be better than the dotted lines.
plt.grid(True, which="majorminor", ls="-", color='0.65')
Note that in the latest version of matplotlib this argument is replaced by 'both'.
plt.grid(True, which="both", ls="-", color='0.65')