Bokeh, combination of bar and line chart - bokeh

I am trying to plot a line on top of a bar chart within bokeh. I have tried:
p1 = figure()...
p1.renderer.append(Bar(...))
p1.renderer.append(Line(...))
show(p1)
So far I had no luck.

Combination of two or more graphs in one plot in Bokeh is possible using the Basic Glyphs.
For your question we can use line and rect.
from bokeh.plotting import figure, output_file, show
from bokeh.models.ranges import Range1d
import numpy
output_file("line_bar.html")
p = figure(plot_width=400, plot_height=400)
# add a line renderer
p.line([1, 2, 3, 4, 5], [6, 7, 6, 4, 5], line_width=2)
# setting bar values
h = numpy.array([2, 8, 5, 10, 7])
# Correcting the bottom position of the bars to be on the 0 line.
adj_h = h/2
# add bar renderer
p.rect(x=[1, 2, 3, 4, 5], y=adj_h, width=0.4, height=h, color="#CAB2D6")
# Setting the y axis range
p.y_range = Range1d(0, 12)
p.title = "Line and Bar"
show(p)
And the plot we get:

Piggybacking on #tomaskazemekas: While it's probably best to avoid mixing plotting and chart levels within Bokeh, it is possible to modify a high-level chart object using add_glyph:
from bokeh.charts import Bar, output_file, show
from bokeh.models.ranges import Range1d
from bokeh.models import ColumnDataSource
from bokeh.models.glyphs import Line as Line_glyph
import numpy as np
# create dummy data
df = dict(
x=[1, 2, 3, 4, 5],
y=[6, 7, 6, 4, 5],
h=[2, 8, 5, 10, 7]
)
# create high-level bar chart
p = Bar(data=df, label='x', values='h', color='dodgerblue', title="Bar and Line Plot",
legend=False, plot_width=400, plot_height=400)
# create source data object from data
source = ColumnDataSource(data=df)
# create a line glyph object which references columns from source data
glyph = Line_glyph(x='x', y='y', line_color='grey', line_width=2)
# add the glyph to the chart
p.add_glyph(source, glyph)
# Setting the y axis range
p.y_range = Range1d(0, 12)
output_file("line_bar.html")
show(p)
Results in a similar plot:
Bar and Line Plot

Related

Changing grid position in Bokeh

I'm trying to make a table to represent the relationship between categorical values based on their count. This is my current code:
source = ColumnDataSource(df)
mapper = LinearColorMapper(palette=brewer['YlGnBu'][4], low=df['count'].min(), high=df['count'].max())
tooltips = [
("Resource", "#org:resoure"),
("Activity", "#concept:name"),
("Count", "#count"),
]
p = figure(plot_width=df['org:resource'].nunique()*180, plot_height=df['concept:name'].nunique()*100, title="US Unemployment 1948—2016",
y_range=df['concept:name'].unique(), x_range=df['org:resource'].unique(),x_axis_location="above", tooltips=tooltips)
p.rect(y="concept:name", x="org:resource", width=1, height=1, source=source,
line_color=None, fill_color=transform('count', mapper))
color_bar = ColorBar(color_mapper=mapper, location=(0, 0),
ticker=BasicTicker(),
formatter=PrintfTickFormatter(format="%d%%"))
p.add_layout(color_bar, 'right')
p.axis.axis_line_color = None
p.axis.major_tick_line_color = None
p.axis.major_label_text_font_size = "13px"
p.axis.major_label_standoff = 0
p.xaxis.major_label_orientation = 0
output_notebook()
show(p)
However, this code produces a grid that does not suite categorical values. How can I shift the grid down?
current visual produced by code
You can achieve this using a FixedTicker.
Here is a very basic example where p.rect() is used.
old
new
The code is very similar, except the ticks are shifted by 0.5 on both axis in the new version using the FixedTicker I mentioned.
old
from bokeh.plotting import figure, output_file, show
data = [1, 5]
plot = figure(plot_width=300, plot_height=300)
plot.rect(x=data, y=data, width=1, height=1, color="#CAB2D6")
show(plot)
new
from bokeh.plotting import figure, output_file, show
from bokeh.models import FixedTicker
data = [1, 5]
plot = figure(plot_width=300, plot_height=300)
plot.rect(x=data, y=data, width=1, height=1, color="#CAB2D6")
_max = max(data)
plot.xaxis.ticker = FixedTicker(ticks=[x+0.5 for x in range(_max+1)])
plot.yaxis.ticker = FixedTicker(ticks=[x+0.5 for x in range(_max+1)])
show(plot)

R - adding legend to plot where par(mfrow = c(2, 1))

I'm trying to add a legend to a plot which is the top plot of a two plot figure. However, the legend is getting massively stretched out so that nothing can be seen and it obscures the end of the plot. Here is the code to reproduce the problem:
cars = c(1, 3, 6, 4, 9)
par(mfrow = c(2, 1), mar=c(5,5,2,2))
plot(cars)
legend("topright", legend=c("label1", "label2"))
And here is what it looks like:
Is there some way to fix this?

ValueError: expected an element of either Enum('solid', 'dashed', 'dotted', 'dotdash', 'dashdot')

I'm attempting to output a line graph with the dash being driven by the data. My example is:
from bokeh.plotting import figure, output_notebook, show
output_notebook()
x = [1, 2, 3, 4, 5]
y = [6, 7, 2, 4, 5]
z = ['dashed', 'dashed', 'dashed', 'solid', 'solid']
p = figure(plot_width=400, plot_height=400)
p.line(x, y, line_width=2, line_dash=z)
show(p)
However, this results in:
ValueError: expected an element of either Enum('solid', 'dashed', 'dotted', 'dotdash', 'dashdot'), Regex('^(\d+(\s+\d+)*)?$') or Seq(Int), got ['dashed', 'dashed', 'dashed', 'solid', 'solid']
Is it possible to set the line type based on my dataset?
It's not possible to set the line dash using a list for the line glyph.
A few things that could help you resolve your issue. Try using the MultiLine glyph for the plot and the ColumnDataSource to structure your data. Using the MultiLine glyph it is possible to set some line properties to change for each segment of the multi line. line_color can be changed for each segment that way, but unfortunately the line_dash property cannot.
You could try opening an issue on Bokeh's Github to allow the line_dash property in the MultiLine glyph to be set from a ColumnDataSource.
Here's an exemple of what a solution could look like.
from bokeh.plotting import figure, show
from bokeh.models import ColumnDataSource
from bokeh.models.glyphs import MultiLine
source = ColumnDataSource(data=dict(z=['dashed', 'dashed', 'solid', 'solid'],
xs=[[1, 2], [2, 3], [3, 4], [4, 5]],
ys=[[6, 7], [7, 2], [2, 4], [4, 5]],
color=['green', 'red', 'green', 'green']))
p = figure(plot_width=400, plot_height=400)
glyph = MultiLine(xs='xs', ys='ys', line_color = 'color', line_dash='z', line_width=2)
p.add_glyph(source, glyph)
show(p)
In the above code, the color can be set using the ColumnDataSource this can be used to distinguish the segments, but the line_dash property will still produce the error.

Aligning grid lines in R, bReeze package

I am trying to get grid lines work properly in the image below. Using the bReeze package to plot the power curves of the turbines with:
library(bReeze)
pc=pc("Vestas_V90_1.8MW.wtg")
plot(pc)
The output plot is:
but assigning grid lines to the plot with the help of:
grid()
gives the image below:
Any suggestions on how to fix the distorted grid lines?
If you don't give some arguments (e.g., mar, xlim, ylim),
plot(pc) uses par(mar = c(5, 5, 1, 5) and treats data.ranges as xlim and ylim. By using these properties, you can use grid().
pc.data = pc("Vestas_V90_1.8MW.wtg")
plot(pc.data)
par(mar = c(5, 5, 1, 5), new=T) # set par() and order to overlay
plot(pc.data[[1]], pc.data[[2]], type="n", ann=F, axes=F) # nothing but setting xy-cordinates
grid(NULL) # here, the same xy-coordinates are reproduced
# If you want to adjust grid lines to right y-axis, use berow code
:
par(mar = c(5, 5, 1, 5), new=T) # plot(pc) uses right ylim=c(0,1)
plot(pc.data[[1]], pc.data[[2]], ylim=c(0,1), type="n", ann=F, axes=F)
grid(NULL) # the xy(right)-coordinates are reproduced
# If you plot pc.object having single y-axis, use mar = c(5, 5, 1, 1)

Initialize y-axis to be centered at 0

I'm generating some line plots that show percent error results. It would be nice if the y-axis was centered at 0 when the plots first load. I know I can manually set the bounds for the y-axis, but it would be tedious to have to set them manually for each figure.
Is there a way to set the figures to center at 0 along the y-axis?
Here's some code that may provide additional details -
from bokeh.plotting import figure, output_file, show
from bokeh.io import gridplot, hplot
# prepare some data
x = [1, 2, 3, 4, 5]
y1 = [-10, -9, 23, 4, -6]
y2 = [-15, -4, 26, 32, -45]
y3 = [-42, -20, -13, -34, -59]
y4 = [-23, -34, -32, -43, -53]
# output to static HTML file
output_file("lines.html", title="line plot example")
# create a new plot with a title and axis labels
p = figure(title="simple line example", x_axis_label='x', y_axis_label='y')
p.line(x, y1, line_width=2)
p.line(x, y2, line_width=2)
p2 = figure(title="simple line example", x_axis_label='x', y_axis_label='y')
p2.line(x, y3, line_width=2)
p2.line(x, y4, line_width=2)
p = hplot(p, p2)
show(p)
This generates two plots. The one on the right shows the problem I'm running into. Since all of the values are negative, the y-axis bounds are narrowed to approximately -10 to -60. I would like that chart to be bound at -60 to 60, so that it's aligned at 0.
Update:
I ended up just defining a function that will return the absolute max of the y values. Then, I am doing the following to set the limits:
axisLimit = getAxisRange(list1, list2) #get absolute max from the two lists
p.y_range = Range1d(start=-1*axisLimit, end=axisLimit)
There's no Bokeh method to center a plot around an axis like you describe. What did you did in your update seems like a good solution. You're always welcome to open an issue on the Bokeh project tracker at https://github.com/bokeh/bokeh/issues

Resources