简体   繁体   English

如何将带有偏移量的箭头注释添加到带有日期时间 x 轴的散景 plot

[英]How to add Arrow annotations with an offset to a bokeh plot with a datetime x-axis

I want to draw an arrow or dots when 2 ma cross each other like there will up arrow when short ma cross above long ma etc. but I don't know how to plot when it is datetime.我想在 2 ma 相互交叉时画一个箭头或点,就像当 short ma 交叉在 long ma 上方时会有向上箭头等。但我不知道如何在日期时间 plot。 I try to use this code and it just give me errors.我尝试使用此代码,但它只会给我错误。

#plot short ma and long ma
p.line(df['Date'], df['short_ma'], color='red')
p.line(df['Date'], df['long_ma'], color='black')

p.add_layout(Arrow(end=VeeHead(size=35), line_color="red",x_start=df['Date'], y_start=df['crossabove']+5, x_end=df['Date'], y_end=df['Date']))
#the crossabove + 5 so the arrow draw above where the cross occur 

I post an image for the result i was expect the result i expect我张贴了我期待的结果的图片 我期待的结果

code to plot candlestick chart and add arrow when 2 ema cross代码为 plot 烛台图表并在 2 EMA 交叉时添加箭头

import pandas as pd
import numpy as np
import timeit
import talib as tb
import datetime
import random
from bokeh.models import Arrow, NormalHead, OpenHead, VeeHead
from bokeh.plotting import figure, output_file, show

df =  pd.read_csv("D:/testdata/msft.csv") #open csv
df['short_ema'] = tb.EMA(df['Close'], 100) # short ema
df['long_ema'] = tb.EMA(df['Close'], 200)  #long ema
df = df.round(2)    #round to 2
df['Date']=pd.to_datetime(df['Date'])
#print(df.dtypes)
#chart figures
p = figure(plot_width=1400, plot_height=860,
           x_axis_type='datetime',)

#candle
inc = df.Close > df.Open
dec = df.Open > df.Close
w = 12*60*60*1000 # half day in ms
p.segment(df['Date'], df['High'], df.Date, df.Low, color="black")
p.vbar(df['Date'][inc], w, df.Open[inc], df.Close[inc], fill_color="#D5E1DD", line_color="black")
p.vbar(df['Date'][dec], w, df.Open[dec], df.Close[dec], fill_color="#F2583E", line_color="black")

#ma lines
p.line(df['Date'], df['short_ema'], color='red')
p.line(df['Date'], df['long_ema'], color='black')
                                     
#df.to_csv("D:/testdata/msft result.csv")

#loop for cross add arrow
match = df[((df.short_ema.shift(1) > df.long_ema.shift(1)) & (df.short_ema.shift(2)< df.long_ema.shift(2)))]

for x_, (y_, _) in match[['Date', 'long_ema']].iterrows():
    print(x_,y_)
    p.add_layout(Arrow(end=VeeHead(line_color="blue", line_width=4, fill_color='blue'),
                       line_color='blue', line_width=4,
                       x_start=df['Date'], y_start= y_ + 3,
                       x_end=df['Date'], y_end=y_ + 1))

show(p)

在此处输入图像描述

  • For an Arrow , x_start and x_end must be a datetime format, not a string or a dataframe .对于Arrowx_startx_end必须是datetime时间格式,而不是stringdataframe
    • x_start=pd.to_datetime('2010-10-09')
    • The coordinates for the arrow may not be passed as a dataframe, they must be passed as individual values, which is done in a loop below.箭头的坐标不能作为 dataframe 传递,它们必须作为单独的值传递,这是在下面的循环中完成的。
      • x_ is the date from the datetime index. x_是日期时间索引中的日期。
      • y_ is the y intersection point, to which an offset (eg +5 ) may be added y_是 y 交点,可以向其添加偏移量(例如+5
  • This example was used, and arrows were added to it使用了此示例,并在其中添加了箭头
  • See Labels for text annotations请参阅文本注释的标签
import pandas as pd
from bokeh.models import Arrow, NormalHead, OpenHead, VeeHead, Label
from bokeh.plotting import figure, show
from bokeh.sampledata.glucose import data
from bokeh.io import output_notebook, curdoc  # output_file
output_notebook()

# for a file, uncomment the next line and output_file in the imports
# output_file("box_annotation.html", title="box_annotation.py example")

TOOLS = "pan,wheel_zoom,box_zoom,reset,save"

#reduce data size
data = data.loc['2010-10-06':'2010-10-13'].copy()

# test line to show where glucose and line cross each other
data['line'] = 170

# determine where the lines cross
match = data[data.glucose == data.line]

p = figure(x_axis_type="datetime", tools=TOOLS)

p.line(data.index.to_series(), data['glucose'], line_color="gray", line_width=1, legend_label="glucose")
p.line(data.index.to_series(), data['line'], line_color="purple", line_width=1, legend_label="line")

# add arrows to all spots where the lines are equal
for x_, (y_, _) in match[['glucose', 'line']].iterrows():
    
    p.add_layout(Arrow(end=VeeHead(line_color="blue", line_width=4, fill_color='blue'),
                       line_color='blue', line_width=4,
                       x_start=x_, y_start= y_ + 130,
                       x_end=x_, y_end=y_ + 5))

p.title.text = "Glucose Range"
p.xgrid[0].grid_line_color=None
p.ygrid[0].grid_line_alpha=0.5
p.xaxis.axis_label = 'Time'
p.yaxis.axis_label = 'Value'

show(p)

在此处输入图像描述

Update更新

  • In the following section:在以下部分中:
    • x_start=df['Date'] & x_end=df['Date'] are used instead of x_ , which should be a single date value, not a Series of dates. x_start=df['Date'] & x_end=df['Date']而不是x_ ,它应该是单个日期值,而不是Series日期。
    • The for-loop selects the incorrect values to be x_ and y_ . for-loop选择了不正确的值x_y_ In my original match , the dates are in the index, but your match has dates in a column.在我原来的match ,日期在索引中,但你的match在一列中有日期。
match = df[((df.short_ema.shift(1) > df.long_ema.shift(1)) & (df.short_ema.shift(2)< df.long_ema.shift(2)))]

for x_, (y_, _) in match[['Date', 'long_ema']].iterrows():
    print(x_,y_)
    p.add_layout(Arrow(end=VeeHead(line_color="blue", line_width=4, fill_color='blue'),
                       line_color='blue', line_width=4,
                       x_start=df['Date'], y_start= y_ + 3,
                       x_end=df['Date'], y_end=y_ + 1))

Corrected Code更正代码

for _, (x_, y_) in match[['Date', 'long_ema']].iterrows():
    print(x_,y_)
    p.add_layout(Arrow(end=VeeHead(line_color="blue", line_width=4, fill_color='blue'),
                       line_color='blue', line_width=4,
                       x_start=x_, y_start= y_ + 3,
                       x_end=x_, y_end=y_ + 1))

show(p)

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM