My code for the bokeh HoverTool is the following:
p = figure(
plot_height=250,
x_axis_type='datetime',
)
p.vbar(x=data_df['date'].dt.to_pydatetime(), top=data_df['data'].values, width=datetime.timedelta(1))
hover_tool = HoverTool(
tooltips=[('Count', '#top'), ('Date', '#x')], mode='vline', formatters={'$x': 'datetime'}
)
p.add_tools(hover_tool)
I still get the numeric format of the date as can be seen on the image. I tried formatters={'#x': 'datetime'} with no luck.
Your solution works, if you use $x instead of #x and add one of the listed formats supported by the DatetimeTickFormatter to ('Date', '$x') like ('Date', '$x{%F}'). There are plenty of options and you can select the one you prefere the most.
Minimal Example
import pandas as pd
from bokeh.plotting import show, figure, output_notebook
from bokeh.models import HoverTool, ColumnDataSource
output_notebook()
data_df = pd.DataFrame({'date':pd.date_range('2022-05-13', freq='D', periods=10), 'top':list(range(10))})
p = figure(
plot_height=250,
x_axis_type='datetime',
)
p.vbar(x=data_df['date'], top=data_df['top'], width=pd.Timedelta('12H'))
hover_tool = HoverTool(
tooltips=[('Count', '#top'), ('Date', '$x{%F}')], mode='vline', formatters={"$x": "datetime"}
)
p.add_tools(hover_tool)
show(p)
Comment:
I don't know why there is no working default, but maybe because there are so many options, that any default would be somehow wrong.
Related
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
As shown below I used the example code of the Bokeh library. I tried add the hovertool and edit the output of the hovertool, but there are only "???" shown.
Can anybody give me a tip, to add and configure the hover tool in the example code?
import pandas as pd
from bokeh.palettes import Spectral4
from bokeh.plotting import figure, output_file, show
from bokeh.sampledata.stocks import AAPL, IBM, MSFT, GOOG
p = figure(plot_width=800, plot_height=250, x_axis_type="datetime")
p.title.text = 'Click on legend entries to hide the corresponding lines'
for data, name, color in zip([AAPL, IBM, MSFT, GOOG], ["AAPL", "IBM", "MSFT", "GOOG"], Spectral4):
df = pd.DataFrame(data)
df['date'] = pd.to_datetime(df['date'])
p.line(df['date'], df['close'], line_width=2, color=color, alpha=0.8, legend=name)
p.legend.location = "top_left"
p.legend.click_policy="hide"
output_file("interactive_legend.html", title="interactive_legend.py example")
show(p)
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)
Question
Below code is grouped vbar chart example from bokeh documentation.
There are something i can't understand on this example.
Where 'cyl_mfr' is come from in factor_cmap() and vbar()?
'mpg_mean' , is it calculating the mean of 'mpg' column? if then,
why 'mpg_sum' doesn't work?
I want to make my own vbar chart like this example.
Code
from bokeh.io import show, output_file
from bokeh.models import ColumnDataSource, HoverTool
from bokeh.plotting import figure
from bokeh.palettes import Spectral5
from bokeh.sampledata.autompg import autompg_clean as df
from bokeh.transform import factor_cmap
output_file("bars.html")
df.cyl = df.cyl.astype(str)
df.yr = df.yr.astype(str)
group = df.groupby(('cyl', 'mfr'))
source = ColumnDataSource(group)
index_cmap = factor_cmap('cyl_mfr', palette=Spectral5,
factors=sorted(df.cyl.unique()), end=1)
p = figure(plot_width=800, plot_height=300, title="Mean MPG by # Cylinders
and Manufacturer",
x_range=group, toolbar_location=None, tools="")
p.vbar(x='cyl_mfr', top='mpg_mean', width=1, source=source,
line_color="white", fill_color=index_cmap, )
p.y_range.start = 0
p.x_range.range_padding = 0.05
p.xgrid.grid_line_color = None
p.xaxis.axis_label = "Manufacturer grouped by # Cylinders"
p.xaxis.major_label_orientation = 1.2
p.outline_line_color = None
p.add_tools(HoverTool(tooltips=[("MPG", "#mpg_mean"), ("Cyl, Mfr",
"#cyl_mfr")]))
show(p)
The group = df.groupby(('cyl', 'mfr')) makes a <pandas.core.groupby.DataFrameGroupBy object at 0x0xxx>. If you pass this to a ColumnDataSource, bokeh does a lot of magic, and calculates a lot of statistics already
df.columns
Index(['mpg', 'cyl', 'displ', 'hp', 'weight', 'accel', 'yr', 'origin', 'name', 'mfr'],
source.column_names
['accel_count', 'accel_mean', 'accel_std', 'accel_min',
'accel_25%', 'accel_50%', 'accel_75%', 'accel_max', 'displ_count',
'displ_mean', 'displ_std', 'displ_min', 'displ_25%', 'displ_50%',
'displ_75%', 'displ_max', 'hp_count', 'hp_mean', 'hp_std',
'hp_min', 'hp_25%', 'hp_50%', 'hp_75%', 'hp_max', 'mpg_count',
'mpg_mean', 'mpg_std', 'mpg_min', 'mpg_25%', 'mpg_50%',
'mpg_75%', 'mpg_max', 'weight_count', 'weight_mean', 'weight_std',
'weight_min', 'weight_25%', 'weight_50%', 'weight_75%',
'weight_max', 'yr_count', 'yr_mean', 'yr_std', 'yr_min',
'yr_25%', 'yr_50%', 'yr_75%', 'yr_max', 'cyl_mfr']
the cyl_mfr is the labels of the 2 columns on which you grouped by concatenated. In source this has become a column of tuples
mpg_sum is not calculated. If you cant the sum, you will need to calculate that yourself.
I have a simple pandas.DataFrame:
df = pd.DataFrame(
{
"name": ['foo','bar'],
"kpi1": [1,2],
"kpi2": [2,1]
}
)
Which I want to scatter plot using Bokeh. First step is:
import bokeh.plotting as bpl
import bokeh.models as bmo
bpl.output_notebook()
p = bpl.figure(tools=["hover"])
p.scatter(
'kpi1',
'kpi2', source=source)
bpl.show(p) # open a browser
Next, I want to configure the tooltip. In particular I want to see the index of each point and the associated name. Here's the second step:
source = bpl.ColumnDataSource.from_df(df)
hover = bmo.HoverTool(
tooltips=[
("index", "$index"),
('Name', '$name')
]
)
p = bpl.figure(tools=[hover])
p.scatter(
'kpi1',
'kpi2', source=source)
bpl.show(p) # open a browser
This works partially. The tooltip contains two fields (index and Name) but the latter is filled with ???. How can I make it read the right column from the dataframe and use it for the tooltip's field?
That is because you call the tooltips with $ instead of #.
The correct definition would be
hover = bmo.HoverTool(
tooltips=[
("index", "#index"),
('Name', '#name')
]
)
By the way, you don't need to to import bokeh.plotting and bokeh.models as a variable. You can sinmply do:
from bokeh.plotting import figure, ColumnDataSource
from bokeh.io import output_file, show
from bokeh.models import HoverTool
and then
# Create a ColumnDataSource from df: source
source = ColumnDataSource(df)
# Create the figure: p
p = figure(tools=["hover"])
# Add circle glyphs to the figure p
p.circle('kpi1', 'kpi2', source= source)
show(p)
hover = HoverTool(tooltips=[("index", "#index"),
('Name', '#name')])
p.add_tools(hover)
show(p)