I'd like to create a line chart but with 2 distinct Y axis with a different scale to replace this piece of code which generates 2 charts:
ch = chartify.Chart(blank_labels=True)
ch.set_title("Elbow method with Euclidian distance")
ch.plot.line(
data_frame=df_elbow,
x_column='K',
y_column='Distortion',
line_width=1)
ch.show()
ch = chartify.Chart(blank_labels=True)
ch.set_title("Elbow method with sum of squared errors")
ch.plot.line(
data_frame=df_elbow,
x_column='K',
y_column='SSE',
line_width=1)
ch.show()
Thanks !
Update:
2nd y-axis plots have been implemented! See chartify.examples.chart_second_axis()
Old answer:
At the moment there isn't support for 2nd y-axis plots, but I'll add in an issue for it. Thanks for the suggestion!
For now I'd suggest falling back on Bokeh. See an example here.
Thanks, here is what I did using the Bokeh figure while waiting for chartify to support 2 axis:
import bokeh.plotting
from bokeh.models import LinearAxis, Range1d
ch = chartify.Chart(blank_labels=True)
ch.set_title("Elbow method to find optimal K")
ch.set_subtitle("Euclidian distance (Blue) and sum of squared errors (Red)")
ch.figure.y_range = Range1d(5, 14)
ch.figure.line(x=df_elbow['K'], y=df_elbow['Distortion'], line_width=1, line_color="Blue")
ch.figure.extra_y_ranges = {"sum": Range1d(start=200000, end=1200000)}
ch.figure.add_layout(LinearAxis(y_range_name="sum"), 'right')
ch.figure.line(x=df_elbow['K'], y=df_elbow['SSE'], line_width=1, y_range_name='sum', line_color="Red")
ch.show()
Related
I would like to add multiple y axes to a bokeh plot (similar to the one achieved using matplotlib in the attached image).
Would this also be possible using bokeh? The resources I found demonstrate a second y axis.
Thanks in advance!
Best Regards,
Pranit Iyengar
Yes, this is possible. To add a new axis to the figure p use p.extra_y_ranges["my_new_axis_name"] = Range1d(...). Do not write p.extra_y_ranges = {"my_new_axis_name": Range1d(...)} if you want to add multiple axis, because this will overwrite and not extend the dictionary. Other range objects are also valid, too.
Minimal example
from bokeh.plotting import figure, show, output_notebook
from bokeh.models import LinearAxis, Range1d
output_notebook()
data_x = [1,2,3,4,5]
data_y = [1,2,3,4,5]
color = ['red', 'green', 'magenta', 'black']
p = figure(plot_width=500, plot_height=300)
p.line(data_x, data_y, color='blue')
for i, c in enumerate(color, start=1):
name = f'extra_range_{i}'
lable = f'extra range {i}'
p.extra_y_ranges[name] = Range1d(start=0, end=10*i)
p.add_layout(LinearAxis(axis_label=lable, y_range_name=name), 'left')
p.line(data_x, data_y, color=c, y_range_name=name)
show(p)
Output
Official example
See also the twin axis example (axis) on the official webpage. This example uses the same syntax with only two axis. Another example is the twin axis example for models.
I had a homework problem recently where we were given a data set and asked to calculate some parameters for a model distribution, with confidence intervals. I wanted to make a quick plot with error bars to display the data, but I can't get the Whisker to show up at all. I'm using Bokeh 2.2.1 so I don't think it's a problem with the version, and the example whisker code from the Bokeh documentation works as well.
Here is the code I wrote for the plot:
from bokeh.io import show
from bokeh.models import ColumnDataSource, Whisker
from bokeh.plotting import figure
from bokeh.transform import factor_cmap
groups= ['Het', 'Wt', 'Mut']
vals = [mle_het[0], mle_wt[0], mle_mut[0]]
upper = [conf_int_het[1][0], conf_int_wt[1][0], conf_int_mut[1][0]]
lower = [conf_int_het[0][0], conf_int_wt[0][0], conf_int_mut[0][0]]
source = ColumnDataSource(data=dict(groups=groups, vals=vals, upper=upper, lower=lower))
p = figure(x_range=groups, plot_height=350, title="Mu MLEs with Error Bars # 95% Confidence Interval", y_range=(0,40))
p.add_layout(
Whisker(source=source, base="groups", upper="upper", lower="lower")
)
p.circle(x='groups', y = 'vals', size=15, source=source, legend_group="groups",
line_color='white', fill_color=factor_cmap('groups', palette=["#962980","#295f96","#29966c"],
factors=groups))
p.xgrid.grid_line_color = None
p.legend.orientation = "horizontal"
p.legend.location = "top_center"
show(p)
The vals, upper, and lower lists are just three floats each that I'm pulling from the data earlier in the code.
There's a link to the plot I'm getting, everything shows up fine except the error bars. I don't get any error messages either. If anyone has any idea how to fix it I'd be grateful!
plot1
This is a bug that'll be fixed in 2.3:
https://github.com/bokeh/bokeh/issues/10575
I plotted the following using plotly and got the resulting plot shown before. X is the # of hours in a day, Y is a proportion between 0-1, and Z is a categorical variable with levels {0,1,2}.
However, it's unclear why the X seems to be going the opposite direction of what we're used to with a 3D Cartesian place where it's down(-) and up(+), left(-) and right(+), and front(-) and back(+). However, X seems to decrease from front to back instead of increase. I am new to plotly and am not sure how to flip the axis so it goes from 0 to 1 instead of 1 to 0. I would greatly appreciate help on this!
fig = px.scatter_3d(X_combined, x='x', y='y', z='z',
color='set', symbol='predictions', opacity=0.7)
fig.update_traces(marker=dict(size=12,
line=dict(width=5,
color='Black')),
selector=dict(mode='markers'))
For 3D plots, the options for axes are under layout.scene.
The autorange option is therefore located under layout.scene.xaxis.autorange and can be modified like this:
fig.update_scenes(xaxis_autorange="reversed")
References:
python/3d-axes
python/layout-scene-xaxis-autorange
This should do the trick:
fig.update_xaxes(autorange="reversed")
Alternatively, you can reverse it with a specific range:
fig.update_xaxes(range=[9, 3])
I would like to use kernel density estimate of seaborn.
First I would like to add a colorbor for the main plot.
Second I would like to add horizontal line to the joint probability distribution to show the 68%, 98% confidence levels and another line which shows the true value
Third I also would like to remove the legend in the plot, considering the following example:
import numpy as np
import pandas as pd
import seaborn as sns
sns.set_context("paper")
# Generate a random correlated bivariate dataset
rs = np.random.RandomState(5)
mean = [0, 0]
cov = [(1, .5), (.5, 1)]
x1, x2 = rs.multivariate_normal(mean, cov, 500).T
x1 = pd.Series(x1, name="$X_1$")
x2 = pd.Series(x2, name="$X_2$")
# Show the joint distribution using kernel density estimation
g = sns.jointplot(x1, x2, kind="kde", size=7, space=0, color="r")
How should I do it?
Not easily possible (although the density values are not particularly interpretable anyway).
These are matplotlib objects, you can add any additional plot elements you want to them.
stat_func=None, as is shown here.
AFAIK you can't do any of those per doc.
I would like to add a colorbor for the main plot.
That's no an option with jointplot. Colorbars are only available with heatmap, clustermap, and interactplot
I would like to add horizontal line to the joint probability distribution to show the 68%, 98% confidence levels and another line
which shows the true value
Not an option as well, the closest you can come to that is overlay two graphs
I also would like to remove the legend in the plot
I'm assuming you're talking about the pearsonr and p values. Those aren't legends and no documentation to show a way to remove them.
Is there a way to plot an infinite horizontal line with Bokeh?
The endpoints of the line should never become visible, no matter how far out the user is zooming.
This is what I've tried so far. It just prints an empty canvas:
import bokeh.plotting as bk
import numpy as np
p = bk.figure()
p.line([-np.inf,np.inf], [0,0], legend="y(x) = 0")
bk.show(p)
One way would be to set the endpoints extremely high/low and the figure's x_range and y_range very small in relation to them.
import bokeh.plotting as bk
import numpy as np
p = bk.figure(x_range=[-10,10])
p.line([-np.iinfo(np.int64).max, np.iinfo(np.int64).max], [0,0], legend="y(x) = 0")
bk.show(p)
However, I am hoping that somebody has a more elegant solution.
Edit: removed outdated solution
You are looking for "spans":
Spans (line-type annotations) have a single dimension (width or height) and extend to the edge of the plot area.
Please, take a look at
http://docs.bokeh.org/en/latest/docs/user_guide/annotations.html#spans
So, the code will look like:
import numpy as np
import bokeh.plotting as bk
from bokeh.models import Span
p = bk.figure()
# Vertical line
vline = Span(location=0, dimension='height', line_color='red', line_width=3)
# Horizontal line
hline = Span(location=0, dimension='width', line_color='green', line_width=3)
p.renderers.extend([vline, hline])
bk.show(p)
With this solution users are allowed to pan and zoom at will. The end of the lines will never show up.
The Bokeh documentation on segments and rays indicates the following solution (using ray):
To have an “infinite” ray, that always extends to the edge of the
plot, specify 0 for the length.
And indeed, the following code produces an infinite, horizontal line:
import numpy as np
import bokeh.plotting as bk
p = bk.figure()
p.ray(x=[0], y=[0], length=0, angle=0, line_width=1)
p.ray(x=[0], y=[0], length=0, angle=np.pi, line_width=1)
bk.show(p)
If you plot two rays from the middle they won't get smaller as you zoom in or out since the length is in pixel. So something like this:
p.ray(x=[0],y=[0],length=300, angle=0, legend="y(x) = 0")
p.ray(x=[0],y=[0],length=300, angle=np.pi, legend="y(x) = 0")
But if the user pans in either direction the end of the ray will show up. If you can prevent the user from panning at all (even when they zoom) then this is a little nicer code for a horizontal line.
If the user is able to zoom and pan anywhere they please, there is no good way (as far as I can tell) to get a horizontal line as you describe.
In case you are wondering how to use spans in combination with time series, convert your dates to unix timestamps:
start_date = time.mktime(datetime.date(2018, 3, 19).timetuple())*1000
vline = Span(location=start_date,dimension='height', line_color='red',line_width=3)
Or see this link for a full example.