Bokeh how to add legend to figure created by multi_line method? - bokeh

I'm trying to add legend to a figure, which contains two lines created by multi_line method.
Example:
p = figure(plot_width=300, plot_height=300)
p.multi_line(xs=[[4, 2, 5], [1, 3, 4]], ys=[[6, 5, 2], [6, 5, 7]], color=['blue','yellow'], legend="first")
In this case the legend is only for the first line. When the legend is defined as a list there is an error:
p.multi_line(xs=[[4, 2, 5], [1, 3, 4]], ys=[[6, 5, 2], [6, 5, 7]], color=['blue','yellow'], legend=["first","second"])
Is it possible to add legend to many lines?

Maintainer Note : PR #8218 which will be merged for Bokeh 1.0, allows legends to be created directly for multi line and patches, without any looping.
To make it faster, when you have a lot of data or a big table etc. You can make a for loop:
1) Make a list of colors and legends
You can always import bokeh paletts for your colors
from bokeh.palettes import "your palett"
Check this link: bokeh.palets
colors_list = ['blue', 'yellow']
legends_list = ['first', 'second']
xs=[[4, 2, 5], [1, 3, 4]]
ys=[[6, 5, 2], [6, 5, 7]]
2) Your figure
p = figure(plot_width=300, plot_height=300)
3) Make a for loop throgh the above lists and show
for (colr, leg, x, y ) in zip(colors_list, legends_list, xs, ys):
my_plot = p.line(x, y, color= colr, legend= leg)
show(p)

Maintainer Note: PR #8218 which will be merged for Bokeh 1.0, allows legends to be created directly for multi line and patches, without any looping or using separate line calls.
multi_line is intended for conceptually single things, that happen to have multiple sub-components. Think of the state of Texas, it is one logical thing, but it has several distinct (and disjoint) polygons. You might use Patches to draw all the polys for "Texas" but you'd only want one legend overall. Legends label logical things. If you want to label several lines as logically distinct things, you will have to draw them all separately with p.line(..., legend_label="...")

On more recent releases (since 0.12.15, I think) its possible to add legends to multi_line plots. You simple need to add a 'legend' entry to your data source. Here is an example taken from the Google Groups discussion forum:
data = {'xs': [np.arange(5) * 1, np.arange(5) * 2],
'ys': [np.ones(5) * 3, np.ones(5) * 4],
'labels': ['one', 'two']}
source = ColumnDataSource(data)
p = figure(width=600, height=300)
p.multi_line(xs='xs', ys='ys', legend='labels', source=source)

Related

'stack order' in Gadfly histogram

When plotting a "stacked histogram", I would like the "stack order" to be the same as the legend order - Fair (first / bottom) and Ideal (last / top) - so that the colors are in order from light to dark. Like in this example.
Any idea how to do that? My code so far:
using CSV, DataFrames, Gadfly
download("https://raw.githubusercontent.com/mwaskom/seaborn-data/master/diamonds.csv", "diamonds.csv")
diamonds = DataFrame(CSV.File("diamonds.csv"))
palette = ["#9D95C2", "#B4ADCF", "#C9C4DB", "#DFDCE9", "#F5F3F4"]
plot(
diamonds,
x = :price,
color = :cut,
Geom.histogram(bincount=50),
Scale.x_log10,
Scale.color_discrete_manual(palette..., order = [1, 2, 4, 3, 5]),
Theme(
background_color = "white",
bar_highlight = color("black")
),
)
This is actually not that easy.
There is a somewhat related question at How do I sort a bar chart in ascending or descending order in Julia's Gadfly? (Does anyone know a less hacky way?)
I will probably try to fiddle a bit more, but what you can do is using levels on top of order.
Scale.color_discrete_manual(palette...,
levels = ["Fair", "Good", "Very Good", "Premium", "Ideal"]
order = [1, 2, 4, 3, 5]),
Then you have three lists, one for the colors one for the levels and one for the order. It is a nightmare, but there should be one permutation that looks similar to the seaborn example (I hope).

Bokeh Hovertool for patch

Is the hover tool for patch different than other glyphs? The plot can see the index for circle but not for patch.
output_file("patch.html")
TOOLTIPS = [
("index", "$index"),
]
p = figure(plot_width=400, plot_height=400, tooltips=TOOLTIPS, tools='hover,help')
# add a patch renderer with an alpha an line width
p.patch([1, 2, 3, 4, 5], [6, 7, 8, 7, 3], alpha=0.5, line_width=2)
p.circle([2], [4],size=20, line_width=2)
show(p)
As of Bokeh 1.0.2, hit testing has not been implemented for Patch, i.e. it is invisible as far as the Hover tool is concerned. You could use the vectorized patches glyph method instead:
p.patches([[1, 2, 3, 4, 5]], [[6, 7, 8, 7, 3]], alpha=0.5, line_width=2)
However, this will always only return 0 as the value of $index since there is only just the one patch (whose index is 0). If you are looking to get "index" values for the vertices of the patch, you will need to do something like plot invisible circles at the same locations as the vertices, that are only there for hit-testing purposes (to drive the hover tool)

Bokeh, how do I add the "?" in the configuring plot tool

I could not find the information regarding the helptool on the bokeh documentation. There is an explanation for all other tools but not this one. I am talking about these tools from the toolbar:
http://docs.bokeh.org/en/latest/docs/user_guide/tools.html
I can choose most of the plot tools I want to use with no problem. I want to include the helptool, which is clearly visible just before the bokeh logo, however I cannot find any direct reference to it.
I just tested it(!), if you want the Helptool, which has a "?" sybmol, it will only be included by default if you do not specify the tools displayed with the plot. OK I will go with this but I will have no "?" if I choose the tools.
I understand your problem I think. You are saying that by default the tool panel will include the help tool. When you specify all the tools from scratch, help tool is not included as default.
If you generate the plot without specifying any tools, then list all tools on the plot:
p.tools
>>>>
[PanTool(id='450f2e26-e0e5-4d90-89c4-44d20f2f688b', ...),
WheelZoomTool(id='84011ce1-4f73-4abb-abd1-26a830b70635', ...),
BoxZoomTool(id='adbfb29a-aa7d-4883-8f8f-d12b7c5af139', ...),
SaveTool(id='ff6ba8bb-c487-418d-82e5-28ff0402e2d6', ...),
ResetTool(id='dfac2559-da4c-4902-829d-f795ee0bfd56', ...),
HelpTool(id='1141330c-e9ff-4e5b-a737-3517c24f263e', ...)]
so you can see there is a helptool. Also it is in the documents
http://docs.bokeh.org/en/latest/docs/reference/models/tools.html#bokeh.models.tools.HelpTool
Therefore you can import this tool and add it to the plot in two ways:
from bokeh.plotting import figure, output_file, show
from bokeh.models import HelpTool
output_file("toolbar.html")
# create a new plot with the toolbar below
p = figure(plot_width=400, plot_height=400,
title=None, toolbar_location="below", tools="pan,wheel_zoom,box_zoom,reset")
p.add_tools(HelpTool())
p.circle([1, 2, 3, 4, 5], [2, 5, 8, 2, 7], size=10)
show(p)
Or more simply:
from bokeh.plotting import figure, output_file, show
output_file("toolbar.html")
# create a new plot with the toolbar below
p = figure(plot_width=400, plot_height=400,
title=None, toolbar_location="right",tools = "pan,wheel_zoom,box_zoom,reset,help")
p.circle([1, 2, 3, 4, 5], [2, 5, 8, 2, 7], size=10)
show(p)

ggplot heatmap failing to fill tiles

This (minimal, self-contained) example is broken:
require(ggplot2)
min_input = c(1, 1, 1, 2, 2, 2, 4, 4, 4)
input_range = c(4, 470, 1003, 4, 470, 1003, 4, 470, 1003)
density = c(
1.875000e-01,
5.598958e-04,
0.000000e+00,
1.250000e-02,
3.841146e-04,
0.000000e+00,
1.250000e-02,
1.855469e-04,
0.000000e+00)
df = data.frame(min_input, input_range, density)
pdf(file='problemspace.pdf')
ggplot(df, aes(x=min_input, y=input_range, fill=density)) +
geom_tile()
dev.off()
Producing:
Why are there big gaps?
There are gaps because you don't have data for all of the tiles. If you want to try to fill them in, your only option is to interpolate (assuming you don't have access to additional data). In theory, geom_raster() (a close relative of geom_tile()) supports interpolation. However, according to this github issue, that feature is not currently functional.
As a workaround, however, you can use qplot, which is just a wrapper around ggplot:
qplot(min_input, input_range, data=df, geom="raster", fill=density, interpolate=TRUE)
If there is too much space between the points that you have data for, you will still end up with blank spaces in your graph, but this will extend the range that you can estimate values for.
EDIT:
Based on the example that you posted, this will be the output
As you can see, there is a vertical band of white running through the middle, due to the lack of data points between 2 and 4.

Spidergraph in R

The following is some code that produces various spider graphs:
# Data must be given as the data frame, where the first cases show maximum.
maxmin <- data.frame(
total=c(5, 1),
phys=c(15, 3),
psycho=c(3, 0),
social=c(5, 1),
env=c(5, 1))
# data for radarchart function version 1 series, minimum value must be omitted from above.
RNGkind("Mersenne-Twister")
set.seed(123)
dat <- data.frame(
total=runif(3, 1, 5),
phys=rnorm(3, 10, 2),
psycho=c(0.5, NA, 3),
social=runif(3, 1, 5),
env=c(5, 2.5, 4))
dat <- rbind(maxmin,dat)
op <- par(mar=c(1, 2, 2, 1),mfrow=c(2, 2))
radarchart(dat, axistype=1, seg=5, plty=1, vlabels=c("Total\nQOL", "Physical\naspects",
"Phychological\naspects", "Social\naspects", "Environmental\naspects"),
title="(axis=1, 5 segments, with specified vlabels)")
radarchart(dat, axistype=2, pcol=topo.colors(3), plty=1, pdensity=30, pfcol=topo.colors(3),
title="(topo.colors, fill, axis=2)")
radarchart(dat, axistype=3, pty=32, plty=1, axislabcol="grey", na.itp=FALSE,
title="(no points, axis=3, na.itp=FALSE)")
radarchart(dat, axistype=1, plwd=1:5, pcol=1, centerzero=TRUE,
seg=4, caxislabels=c("worst", "", "", "", "best"),
title="(use lty and lwd but b/w, axis=1,\n centerzero=TRUE, with centerlabels)")
par(op)
The output of the graphs consists of two sets of line segments with different colors. Where did the second set of line segments come from? Also what is a good way to graph multiple items on the same spider graph?
You should mention that you are using the fmsb library to create the graph. The code you show is the example in the documentation. The puzzling thing at first glance is why three sets of lines are shown (not two as you imply with "second set") while there are 5 records in dat.
It is all in that same documentation you took the code from:
row 1 = the maximum values (defined in `maxmin` in the example code)
row 2 = minimum values (defined in `maxmin` in the example code)
row 3 to 5 are example data points, each row leading to one of the
three line segments that you see in the example graphs.
Just read the documentation for radarchart {fmsb} again and play with the numbers in the example as you do so. It should be pretty clear what is happening and what options you have for your own data. You can add as many data-rows and create corresponding lines as you wish. But these do tend to become unreadable if you overdo it.

Resources