How to plot LabelSet outside the plot box? - python

I'm trying to highlight last value of a time series plot by plot its value on yaxis, as shown in this question. I prefer using LabelSet over Legend because you can precisely control the text positions and also using a data source to update it. But unfortunately, I can not find out how to draw label text outside the plot box.
Here is some code to plot LabelSet and notice how the text is only shown inside the box (66.1x is partially blocked by yaxis):
import pandas as pd
from bokeh.io import output_notebook
output_notebook()
from bokeh.plotting import figure, show
from bokeh.models import LabelSet, ColumnDataSource
#import bokeh.sampledata
#bokeh.sampledata.download()
from bokeh.sampledata.stocks import MSFT
df = pd.DataFrame(MSFT)[:50]
df["date"] = pd.to_datetime(df["date"])
p = figure(
x_axis_type="datetime", width=1000, toolbar_location='left',
title = "MSFT Candlestick", y_axis_location="right")
p.line(df.date, df.close)
ds = ColumnDataSource({'x': [df.date.iloc[-1]], 'y': [df.close.iloc[-1]], 'text': [' ' + str(df.close.iloc[-1])]})
ls = LabelSet(x='x', y='y', text='text', source=ds)
p.add_layout(ls)
show(p)
Please let me know how to show LabelSet outside the box, Thanks

Related

bokeh line plot with string x value

I want to make out a bokeh line plot with string x-value but I just get an empty bokeh plot
sample={'A':['2012-01','2012-02','2012-03'],'B':[7,8,9]}
from bokeh.plotting import figure, output_file, show
source2 = ColumnDataSource(sample)
p = figure(width=400, height=400)
p.line(x='A',y='B',source=source2, line_width=2)
output_notebook()
show(p)
Please notice, you should always check the imports. In your example two imports are missing.
To use date representation in bokeh, you can set the x_axis_type to "datetime" but this will enable only the DatetimeFormatter. Befor this, you have to transform the date string somehow into a number. One easy option is to use pandas.to_datetime().
This tutorial shows how to enable datetime axes.
Example
import pandas as pd
from bokeh.plotting import figure, output_notebook, show
from bokeh.models import ColumnDataSource
sample={'A':[pd.to_datetime(x) for x in ['2012-01','2012-02','2012-03']],'B':[7,8,9]}
source = ColumnDataSource(sample)
p = figure(width=400, height=400, x_axis_type='datetime')
p.line(x='A', y='B', source=source, line_width=2)
output_notebook()
show(p)
Output

Bokeh scatter plot: is it possible to overlay a line colored by category?

I have a dataframe that details sales of various product categories vs. time. I'd like to make a "line and marker" plot of sales vs. time, per category. To my surprise, this appears to be very difficult in Bokeh.
The scatter plot is easy. But then trying to overplot a line of sales vs. date with the same source (so I can update both scatter and line plots in one go when the source updates) and in such a way that the colors of the line match the colors of the scatter plot markers proves near impossible.
Minimal reproducible example with contrived data:
import pandas as pd
df = pd.DataFrame({'Date':['2020-01-01','2020-01-02','2020-01-01','2020-01-02'],\
'Product Category':['shoes','shoes','grocery','grocery'],\
'Sales':[100,180,21,22],'Colors':['red','red','green','green']})
df['Date'] = pd.to_datetime(df['Date'])
from bokeh.io import output_notebook
output_notebook()
from bokeh.io import output_file, show
from bokeh.plotting import figure
source = ColumnDataSource(df)
plot = figure(x_axis_type="datetime", plot_width=800, toolbar_location=None)
plot.scatter(x="Date",y="Sales",size=15, source=source, fill_color="Colors", fill_alpha=0.5, \
line_color="Colors",legend="Product Category")
for cat in list(set(source.data['Product Category'])):
tmp = source.to_df()
col = tmp[tmp['Product Category']==cat]['Colors'].values[0]
plot.line(x="Date",y="Sales",source=source, line_color=col)
show(plot)
Here's what it looks like, which is clearly wrong:
Here's what I want and don't know how to make:
Can Bokeh not make such plots, where scatter markers and lines have the same color per category, with a legend?
With bokeh it is often helpful to first think about the visualisation you want and then structuring the data source appropriately. You want two lines, on per category, the x axis is time and y axis is the sales. Then a natural way to structure your data source is the following:
df = pd.DataFrame({'Date':['2020-01-01','2020-01-02'],
'Shoe Sales':[100, 180],
'Grocery Sales': [21, 22]
})
from bokeh.io import output_notebook
output_notebook()
from bokeh.io import output_file, show
from bokeh.plotting import figure
source = ColumnDataSource(df)
plot = figure(x_axis_type="datetime", plot_width=800, toolbar_location=None)
categories = ["Shoe Sales", "Grocery Sales"]
colors = {"Shoe Sales": "red", "Grocery Sales": "green"}
for category in categories:
plot.scatter(x="Date",y=category,size=15, source=source, fill_color=colors[category], legend=category)
plot.line(x="Date",y=category,source=source, line_color=colors[category])
show(plot)
The solutions is to group your data. Then you can plot lines for each group.
Minimal Example
import pandas as pd
from bokeh.plotting import figure, show, output_notebook
output_notebook()
df = pd.DataFrame({'Date':['2020-01-01','2020-01-02','2020-01-01','2020-01-02'],
'Product Category':['shoes','shoes','grocery','grocery'],
'Sales':[100,180,21,22],'Colors':['red','red','green','green']})
df['Date'] = pd.to_datetime(df['Date'])
plot = figure(x_axis_type="datetime",
plot_width=400,
plot_height=400,
toolbar_location=None
)
plot.scatter(x="Date",
y="Sales",
size=15,
source=df,
fill_color="Colors",
fill_alpha=0.5,
line_color="Colors",
legend_field="Product Category"
)
for color in df['Colors'].unique():
plot.line(x="Date", y="Sales", source=df[df['Colors']==color], line_color=color)
show(plot)
Output

Adding single python bokeh label

I am trying to add a single label at a specific spot on a bokeh chart. I know this easy but I can't seem to find the code that works for me.
I am trying to use the Label in bokeh.models but it isn't working.
I know the exact x and y coordinates, text and text color but it isn't working.
Any help will be greatly appreciated.
from bokeh.plotting import figure, output_file, show
from bokeh.io import output_notebook
from bokeh.models.tools import HoverTool
from bokeh.models import Label
output_notebook()
graph = figure(title = "Average Yearly Temperature per US State",)
for state in us_state_temps.columns:
if state == 'California':
graph.line(us_state_temps.index, us_state_temps[state], line_width = 2, color = "red")
else:
graph.line(us_state_temps.index, us_state_temps[state], line_width = 0.5, color = 'gray')
graph.xaxis.axis_label = 'Year'
graph.yaxis.axis_label = "Average Yearly Temperature °C"
graph.toolbar_location = None
graph.toolbar.active_drag = None
california = Label(x=70, y=1960, x_units='screen', y_units='screen', text='California')
graph.add_layout(california)
hover = HoverTool()
hover.tooltips = [('Year', '#x'), ('Average temp.', '#y')]
graph.add_tools(hover)
show(graph)

Bokeh don't show any plot after adding color palette

I want to draw a circle with bokeh, the color of this circle depends on a column of DataFrame. But I got an empty plot. If i don't specify a color argument for p.circle, it'll work fine.
Here is the code, you can copy and paste and run it.
from bokeh.plotting import figure, output_file, show
from bokeh.models import ColumnDataSource, CategoricalColorMapper
from bokeh.palettes import Spectral11
import pandas as pd
df = pd.DataFrame({
'price':[10,15,20,25,30],
'action':[0,1,0,2,3],
'sign':[0,-1,0,1,-1]
})
source = ColumnDataSource(data=dict(
index=df.index,
price=df.price,
action=df.action,
sign=df.sign
))
color_mapper = CategoricalColorMapper(factors= [str(i) for i in list(df.sign.unique())], palette=Spectral11)
p = figure(plot_width=800, plot_height=400)
# this works fine
p.circle('index', 'price', radius=0.2 , source=source)
# this don't work
p.circle('index', 'price', radius=0.2 , color={'field':'sign', 'transform':color_mapper}, source=source)
show(p)
Bokeh doesn't like it when you take some information from a ColumnDataSource, and other information from a different source. This worked for me(in a notebook):
from bokeh.plotting import figure, output_notebook, show
from bokeh.models import ColumnDataSource, CategoricalColorMapper
from bokeh.palettes import Spectral11
import pandas as pd
output_notebook()
df = pd.DataFrame({
'price':[10,15,20,25,30],
'action':[0,1,0,2,3],
'sign':[0,-1,0,1,-1],
})
source = ColumnDataSource(data=dict(
index=df.index,
price=df.price,
action=df.action,
sign=df.sign,
color=[Spectral11[i+1] for i in df.sign]
))
p = figure(plot_width=800, plot_height=400)
# this don't work
p.circle('index', 'price', radius=0.2 ,
color='color',
source=source)
show(p)

Bokeh plot displaying without data

I am running the following code to render a plot with dates in the x axis and floats in the y axis:
import pandas as pd
from bokeh.plotting import figure, output_file, show
from bokeh.models import DatetimeTickFormatter
from bokeh.charts import Bar, Line, show
def datetime(x):
return pd.DataFrame(x, dtype='datetime64')
openxbids = pd.read_csv('data')
openxbids.sort_values('date')
output_file("lines.html")
p = figure(width=800, height=250, x_axis_type="datetime")
p.line(datetime(openxbids['date']), openxbids['bids'], color = 'navy', alpha=0.5)
show(p)
However, when I run this, I get a graph without any data plotted. The x and y axis ranges seem to be correctly detected. What am I missing?

Categories

Resources