I'm running the code from the top answer to this question in an IPython/Jupyter notebook. The first time I run it, it displays properly:
If I change any parameter, no matter how inconsequential (e.g. a single quote to a double quote), when I run the cell again, or when I run the same code in another cell, the following appears:
It looks like it's recursively putting the desired 2x1 grid of subplots inside a new 2x1 grid of subplots. I tried adding bk_plotting.reset_output(), but it had no effect.
Here's the cell code:
import numpy as np
import bokeh.plotting as bk_plotting
import bokeh.models as bk_models
# for the ipython notebook
bk_plotting.output_notebook()
# a random dataset
data = bk_models.ColumnDataSource(data=dict(x=np.arange(10),
y1=np.random.randn(10),
y2=np.random.randn(10)))
# defining the range (I tried with start and end instead of sources and couldn't make it work)
x_range = bk_models.DataRange1d(sources=[data.columns('x')])
y_range = bk_models.DataRange1d(sources=[data.columns('y1', 'y2')])
# create the first plot, and add a the line plot of the column y1
p1 = bk_models.Plot(x_range=x_range,
y_range=y_range,
title="",
min_border=2,
plot_width=250,
plot_height=250)
p1.add_glyph(data,
bk_models.glyphs.Line(x='x',
y='y1',
line_color='black',
line_width=2))
# add the axes
xaxis = bk_models.LinearAxis()
p1.add_layout(xaxis, 'below')
yaxis = bk_models.LinearAxis()
p1.add_layout(yaxis, 'left')
# add the grid
p1.add_layout(bk_models.Grid(dimension=1, ticker=xaxis.ticker))
p1.add_layout(bk_models.Grid(dimension=0, ticker=yaxis.ticker))
# add the tools
p1.add_tools(bk_models.PreviewSaveTool())
# create the second plot, and add a the line plot of the column y2
p2 = bk_models.Plot(x_range=x_range,
y_range=y_range,
title="",
min_border=2,
plot_width=250,
plot_height=250)
p2.add_glyph(data,
bk_models.glyphs.Line(x='x',
y='y2',
line_color='black',
line_width=2))
# add the x axis
xaxis = bk_models.LinearAxis()
p2.add_layout(xaxis, 'below')
# add the grid
p2.add_layout(bk_models.Grid(dimension=1, ticker=xaxis.ticker))
p2.add_layout(bk_models.Grid(dimension=0, ticker=yaxis.ticker))
# add the tools again (it's only displayed if added to each chart)
p2.add_tools(bk_models.PreviewSaveTool())
# display both
gp = bk_plotting.GridPlot(children=[[p1, p2]])
bk_plotting.show(gp)
It is important to specify versions in reports such as this. This bug was noted in this GitHub issue (detailed comment), with a fix recorded as being in put in place in this Pull Request before the 0.8.2 release. I cannot reproduce the problem in a clean Bokeh 0.8.2 conda environent (python3, jupiter/ipython 3.10, OSX+safari) with the code above. If you can still reproduce this problem with Bokeh >= 0.8.2, please file a bug report on Bokeh issue tracker with as much information above versions, platform, etc. as possible.
Related
I have a Quad plot displaying 2 data-sets. I would like to add a legend to the plot, however I am not sure how to do this with the Quad glyph.
Previous examples have used 'legend' however this is now deprecated, and I've tried using
'legend_label' however this is does not work.
My ultimate goal is to use the legend to interactively display both datasets
# Convert dataframe to column data source
src1 = ColumnDataSource(Merged_Bins)
src2 = ColumnDataSource(Merged_Bins)
#------------------------------------------------------------------------------------------------
# Plot Histogram using Bokeh plotting library
#------------------------------------------------------------------------------------------------
plot = figure(y_range=Range1d(start=0, end=Max_Histogram_Value),sizing_mode="scale_width",width=3000,height= 600,
title= "Histogram Plot",
x_axis_label="Time (ms)",
y_axis_label="Count",toolbar_location = "below")
plot.yaxis.ticker = FixedTicker(ticks=list(tick_vals))
glyph1=Quad(bottom=0, top='Delay1', left='left1',
right='right1', fill_color='#FF7F00',
line_color='black', fill_alpha=0.7,line_alpha=0.5,name="Option 2")
glyph1_plot=plot.add_glyph(src1, glyph1)
glyph2=Quad(bottom=0, top='Delay2', left='left2',
right='right2', fill_color='#616261',
line_color='#616261',line_alpha=0.1, fill_alpha=0.1,name="Original Design")
plot.add_glyph(src2, glyph2)
# Add hover tool for when mouse is over data
hover1 = HoverTool(tooltips=[('Delay Envelope', '#Bin_interval'),('Count', '#Delay1'),('Count Original', '#Delay2')],mode='vline',renderers=[glyph1_plot])
plot.add_tools(hover1)
plot.legend.location = "top_left"
plot.legend.click_policy="hide"
# Set autohide to true to only show the toolbar when mouse is over plot
plot.toolbar.autohide = True
script, div = components(plot)
show(plot)
It works just fine if you use the Figure.quad method instead of manually calling Figure.add_glyph with an explicitly created instance of Quad. All legen_* arguments are parsed by glyph methods of the Figure class - the glyph classes themselves do not use them at all.
from bokeh.io import show
from bokeh.plotting import figure
p = figure()
p.quad(-1, 1, 1, -1, legend_label='Hello')
p.quad(1, 3, 3, 1, color='green', legend_label='there')
show(p)
Alternatively, if you really need the manual approach for some reason, you can also create a legend manually by creating an instance of the Legend class and by adding it to the figure with Figure.add_layout.
Also, on an unrelated note - your plot looks like it was created with vbar instead of quad because all bars seem to have the same width. If so, perhaps using vbar would be simpler in your case.
I want to add a second y-axis into a holoviews figure with bokeh backend.
In bokeh, the parameter "extra-y-axis" achieves that.
After searching the holoviews API I did not find any direct command/parameter for that, so - with some hv github research - I tried it with hooks.
But unfortunately I am still struggling to define a finalize/initialize hook to do that.
What I tried (code from holoviews' github):
def twinx(plot, element):
# Setting the second y axis range name and range
start, end = (element.range(1))
label = element.dimensions()[1].pprint_label
plot.state.extra_y_ranges = {"foo": Range1d(start=start, end=end)}
# Adding the second axis to the plot.
linaxis = LinearAxis(axis_label=label, y_range_name='foo')
plot.state.add_layout(linaxis, 'left')
curve_1 = hv.Scatter(data1)
curve_2 = hv.Scatter(data2).opts(plot=dict(finalize_hooks=[twinx]), style=dict(color='red'))
curve_1*curve_2
The result does create a second y-axis, but curve_2 is still plotted against the first y-axis.
How can I solve this? Thank you!
I'm testing geopandas library for a simple exercise : displaying several points on a map, and then superimpose a large circle above to delete a part of them with the difference method.
To check that the transformation works fine, I'm using an iPython notebook to see my different layers.
So, here's the begining of my manipulation :
%matplotlib inline
# this line is just for a correct plotting in an iPython nb
import pandas as pd
import geopandas as gp
from shapely.geometry import Point
df = pd.read_csv("historical_monuments.csv", sep = ",")
geometry = [Point(xy) for xy in zip(fichier.Longitude, fichier.Latitude)]
# I convert two columns of my csv for geographic information displaying
df = df.drop(['Longitude', 'Latitude'], axis = 1)
# just delete two columns of my first df to avoid redundancy
geodf = gp.GeoDataFrame(file, crs=None, geometry=geometry)
Then, to see my points, I just wrote :
geodf.plot(marker='o', color='red', markersize=5)
Here's the result :
That's super fine. Now I just want to add in this layer a point with a large radius. I tried this :
base = gdf.plot(marker='o', color='red', markersize=5)
# the first plotting becomes a variable to reuse it
center_coord = [Point(6.18, 48.696000)]
center = gp.GeoDataFrame(crs=None, geometry=center_coord)
circle = center.buffer(0.001)
Then, I just thought that these command would be enough :
circle.plot(ax=base, color = 'white')
But instead of a graphical displaying, my notebook returns :
<matplotlib.axes._subplots.AxesSubplot at 0x7f763bdde5c0>
<matplotlib.figure.Figure at 0x7f763be5ef60>
And I didn't find what could be wrong so far...
The command
%matplotlib inline
produces a static plot. Once it appears in your notebook it can not be changed anymore. That is why you have to put your code in a single Cell as schlump said.
An alternative would be to switch to the notebook backend, which is interactive and allows you to modify your plot over several Cells. To active it simply use
%matplotlib notebook
instead of inline.
Well my best guess is you didn't execute your code within one Cell... for some strange behaviour the plot does not show up if executed over multiple cells... I could replicate your problem, however when i executed the Code in one cell the plot showed up.
%matplotlib inline
import pandas as pd
import geopandas as gp
import numpy as np
import matplotlib.pyplot as plt
from shapely.geometry import Point
# Create Fake Data
df = pd.DataFrame(np.random.randint(10,20,size=(10, 3)), columns=['Longitude','Latitude','data'])
# create Geometry series with lat / longitude
geometry = [Point(xy) for xy in zip(df.Longitude, df.Latitude)]
df = df.drop(['Longitude', 'Latitude'], axis = 1)
# Create GeoDataFrame
geodf = gp.GeoDataFrame(df, crs=None, geometry=geometry)
# Create Matplotlib figure
fig, ax = plt.subplots()
# Set Axes to equal (otherwise plot looks weird)
ax.set_aspect('equal')
# Plot GeoDataFrame on Axis ax
geodf.plot(ax=ax,marker='o', color='red', markersize=5)
# Create new point
center_coord = [Point(15, 13)]
center = gp.GeoDataFrame(crs=None, geometry=center_coord)
# Plot new point
center.plot(ax=ax,color = 'blue',markersize=5)
# Buffer point and plot it
circle = center.buffer(10)
circle.plot(color = 'white',ax=ax)
ps: Btw you've got some variables mixed up
I am struggling with something and I can't find a reasonable explanation even though I'm certain it's something small that I've overlooked.
While trying to plot a 2x4 subplot in plotly, the first of the 8 graphs is plotted over the entire 8 grids, rather than being in position (1,1) of the subplot. The remaining 7 graphs are plotted as expected, with the first plot partially visible underneith them. This is the code I am using:
#make a new trace (plot) for every sample:
def make_trace(x_list, y_list, samplename):
trace = go.Scatter(
x = x_list,
y = y_list,
name=samplename
)
layout = go.Layout(
title=samplename,
showlegend=True
)
)
return trace, layout
#call the make_trace function for every sample and append to the figure
def make_subplot():
fig = tls.make_subplots(rows=2, cols=4,plot_titles=cols_list)
row_num = [1,1,1,1,2,2,2,2,3,3,3,3]
column_num = [1,2,3,4,1,2,3,4,1,2,3,4]
i = 0
for sample in cols_list[1:]:
trace, layout = make_trace(normalised_df['percentage'],
normalised_df[sample], sample)
fig.append_trace(trace, row_num[i], column_num[i])
i += 1
fig['layout'].update(title='Normalized Mean Coverage', height=600,
width=800,showlegend=False,font=dict(size=14),
xaxis=dict(title="Transcript Length (%)"),
yaxis=dict(title="Normalised Mean Coverage"))
iplot(fig)
#call the function to create the entire figure:
make_subplot()
The output looks like this:
coverage plot
**Last words: The solution seems to lie somewhere in setting the xaxis/yaxis titles... When I change them in 'layout' in the function call rather than calling fig.update() afterwards the subplot works as expected but its just way too small. The problem is that I want to keep make_trace() as a separate function, as I call it later for a combined plot, so I can't change its x/yaxis titles in this function.
You need to set the xaxis and yaxis titles for each subplot individually:
for idx, sample in enumerate(cols_list):
trace, layout = make_trace(normalised_df['percentage'],
normalised_df[sample], sample)
fig.append_trace(trace, row_num[i], column_num[i])
fig['layout']['xaxis{}'.format(idx+1)].update(title='Transcript Length (%)')
fig['layout']['yaxis{}'.format(idx+1)].update(title='Normalised Mean Coverage')
This seems that this was a bug in the plotly library. It has been solved in my case by updating the plotly package to 3.6.0 for R. In Python I do not know if this is also a bug. But if so just do a bug report in github.
Best regards
Sinan
Have you tried setting axis and axis anchors for each of the subplots? Such as this:
t1 = go.Scatter(x=x, y=y1(x), xaxis="x1", yaxis="y1", name="Trace 1")
t2 = go.Scatter(x=x, y=y2(x), xaxis="x2", yaxis="y2", name="Trace 2")
layout = go.Layout(
xaxis1=dict(anchor="y1", domain=[0, 1]),
yaxis1=dict(anchor="x1", domain=[0.25, 0.45]),
xaxis2=dict(anchor="y2", domain=[0.5, 1]),
yaxis2=dict(anchor="x2", domain=[0.8, 1]))
I have found that I can not get axes autoscale to work on the 1st axes after creating a second axes using twinx. Is this expected?
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 10, 0.1)
y1 = 0.05 * x**2
y2 = -1 *y1
fig, axL = plt.subplots() # Make Left Axes
axR = axL.twinx() # Make Left Axes
axL.plot(x, y1, 'g-') # Plot on Left
axL.grid()
axL.autoscale(enable=True, axis=u'both', tight=False)
plt.show()
# Do some stuff then later plot on axR
When I run the above code it autoscales in the y-direction correctly on the left axes (0 to 5) but changes the X-Axis scale to +/- 0.06 instead of the correct 0 to 10. However, once axR is no longer blank and something is plotted on axR it behaves as I would expect.
This is only an example as I first came across this issue in more complicated PyQT4 GUI that allows the user to create multiple subplots & left/right combinations. Since the user is the one manually controlling the plot creation order it is possible for the above situation to present itself.
Is there a way for autoscale to work with a blank twinx right axes. Or is the Xlimit just going to have to be manually set?
FYI, I am using Python 3.4 as part of Anaconda v2.0.1 with Matplotlib v1.3.1
Thanks.
This is merely a workaround than a proper solution or explanation.
Simply add an invisible point in the right axes so it is not completely empty:
axR.plot(0, 0, visible=False)
You have to make sure though, that the invisible point lies within the ranges of the data that you plot in axL. E.g.:
axR.plot(np.mean(x),np.mean(y1),visible=False)
As for an explanation (I'm guessing):
axR.dataLim is [-np.inf, np.inf] initially. The union of axR.dataLim and axL.dataLim still gives [-np.inf, np.inf] which is then collapsed to [0,0].
EDIT: This was fixed recently (here). Upgrading to matplotlib v1.4.* should solve the problem.