时间序列图#
单位#
Bokeh 可以自动处理多种日期时间类型,例如 Numpy 日期时间数组和 Pandas 日期时间序列,以及 Python 内置的日期时间类型。有时了解 Bokeh 如何表示这些值会很有帮助。
在内部,所有日期时间值都是表示自纪元以来的毫秒数的浮点值(具体来说,“纪元”此处指的是Unix 时间,即1970 年 1 月 1 日 00:00:00 UTC)。Bokeh 会将日期时间值转换为这种浮点格式,然后再传递给 BokehJS。有时(例如在CustomJS
回调中),可能需要直接使用这些值。
范围工具#
通常希望能够放大时间序列的一个区域,同时仍然可以看到完整序列的视图以供参考。可以使用RangeTool
在一个图中交互式地定义一个区域,从而在另一个图中获得缩放视图。如下所示
import numpy as np
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, RangeTool
from bokeh.plotting import figure, show
from bokeh.sampledata.stocks import AAPL
dates = np.array(AAPL['date'], dtype=np.datetime64)
source = ColumnDataSource(data=dict(date=dates, close=AAPL['adj_close']))
p = figure(height=300, width=800, tools="xpan", toolbar_location=None,
x_axis_type="datetime", x_axis_location="above",
background_fill_color="#efefef", x_range=(dates[1500], dates[2500]))
p.line('date', 'close', source=source)
p.yaxis.axis_label = 'Price'
select = figure(title="Drag the middle and edges of the selection box to change the range above",
height=130, width=800, y_range=p.y_range,
x_axis_type="datetime", y_axis_type=None,
tools="", toolbar_location=None, background_fill_color="#efefef")
range_tool = RangeTool(x_range=p.x_range, start_gesture="pan")
range_tool.overlay.fill_color = "navy"
range_tool.overlay.fill_alpha = 0.2
select.line('date', 'close', source=source)
select.ygrid.grid_line_color = None
select.add_tools(range_tool)
show(column(p, select))
烛台图#
import pandas as pd
from bokeh.models import BoxAnnotation
from bokeh.plotting import figure, show
from bokeh.sampledata.stocks import MSFT
df = pd.DataFrame(MSFT)[60:120]
df["date"] = pd.to_datetime(df["date"])
inc = df.close > df.open
dec = df.open > df.close
non_working_days = df[['date']].assign(diff=df['date'].diff()-pd.Timedelta('1D'))
non_working_days = non_working_days[non_working_days['diff']>=pd.Timedelta('1D')]
df['date'] += pd.Timedelta('12h') # move candles to the center of the day
TOOLS = "pan,wheel_zoom,box_zoom,reset,save"
p = figure(x_axis_type="datetime", tools=TOOLS, width=1000, height=400,
title="MSFT Candlestick", background_fill_color="#efefef")
p.xaxis.major_label_orientation = 0.8 # radians
boxes = [
BoxAnnotation(fill_color="#bbbbbb", fill_alpha=0.2, left=date-diff, right=date)
for date, diff in non_working_days.values
]
p.renderers.extend(boxes)
p.segment(df.date, df.high, df.date, df.low, color="black")
p.vbar(df.date[dec], pd.Timedelta('16h'), df.open[dec], df.close[dec], color="#eb3c40")
p.vbar(df.date[inc], pd.Timedelta('16h'), df.open[inc], df.close[inc], fill_color="white",
line_color="#49a3a3", line_width=2)
show(p)
缺失日期#
import pandas as pd
from bokeh.plotting import figure, show
from bokeh.sampledata.stocks import MSFT
df = pd.DataFrame(MSFT)[60:120]
df["date"] = pd.to_datetime(df["date"])
inc = df.close > df.open
dec = df.open > df.close
TOOLS = "pan,wheel_zoom,box_zoom,reset,save"
p = figure(tools=TOOLS, width=1000, height=400,
title="MSFT Candlestick without missing dates",
background_fill_color="#efefef")
p.xaxis.major_label_orientation = 0.8 # radians
p.x_range.range_padding = 0.05
# map dataframe indices to date strings and use as label overrides
p.xaxis.major_label_overrides = {
i: date.strftime('%b %d') for i, date in zip(df.index, df["date"])
}
# one tick per week (5 weekdays)
p.xaxis.ticker = list(range(df.index[0], df.index[-1], 5))
p.segment(df.index, df.high, df.index, df.low, color="black")
p.vbar(df.index[dec], 0.6, df.open[dec], df.close[dec], color="#eb3c40")
p.vbar(df.index[inc], 0.6, df.open[inc], df.close[inc], fill_color="white",
line_color="#49a3a3", line_width=2)
show(p)