Боке: возможно ли создавать глифы на основе условия с ColumnDataSource так же, как с pandas DataFrame? - PullRequest
0 голосов
/ 06 апреля 2020

Ну, я создаю прямоугольники в Bokeh, которые основаны на условии:

rect1 = p.rect(df.index[df.Close > df.Open],(df["Open"][df.index[df.Close > df.Open]]+df["Close"][df.index[df.Close > df.Open]])/2, hours_12, (df["Close"][df.index[df.Close > df.Open]]-df["Open"][df.index[df.Close > df.Open]]),fill_color="#CCCCCC", line_color="black")

Таким образом, он создаст прямоугольник только в том случае, если значение в столбце «Закрыть» больше значения «Открыть». Все работает нормально без создания ColumnDataSource. Если я попытаюсь сделать это с помощью ColumnDataSource, это не сработает, поэтому я скажу: «Эй, все в порядке, я собираюсь придерживаться pandas здесь.

Проблема заключается в попытке использовать HoverTool. Он не любит pandas DataFrame. Поэтому я не в состоянии иметь и условия, и инструмент для наведения. Я должен выбрать один из них.

Есть ли решение для этого?

Большое спасибо

Ответы [ 2 ]

0 голосов
/ 09 апреля 2020

Хорошо, поэтому я нашел решение, главным образом, благодаря этому: Как правильно обрабатывать дату-время и категориальные оси на графике тепловой карты bokeh / holoviews?

У моего кода было две проблемы: когда я был преобразование pandas dataframe в ColumnDataSource Мне нужно было преобразовать дату в объект datetime.

x_green = [
     date.to_datetime64().astype('M8[ms]').astype('O')
     for date in df_green.index.to_list()
]

И потом мне нужно было понять, что я не могу выполнить ту же (математическую) операцию между ColumnDataSource столбцами, как это возможно с pandas столбцами. Поэтому мне нужно было подготовить данные (словарь) из столбцов pandas, затем сделать ColumnDataSource, и тогда мне было разрешено наконец использовать HoverTool, который был основным всегда. Тогда это наконец сработало. Весь код здесь:

from datetime import datetime
from pandas_datareader import data
import pandas as pd
from bokeh.plotting import figure, show, ColumnDataSource, output_file
from bokeh.io import output_notebook
from bokeh.models import HoverTool

output_notebook()

start=datetime(2020,1,1)
end=datetime(2020,4,3)
name="NSRGY" #nestle

#getting stock data from yahoo
df=(data.DataReader(name=name,data_source="yahoo",start=start,end=end))

#making two datasets based on criteria 
df_green=df[df.Close > df.Open]
df_red=df[df.Close < df.Open]

#converting date to datetime : otherwise ColumnDataSource is not working
x_green = [
     date.to_datetime64().astype('M8[ms]').astype('O')
     for date in df_green.index.to_list()
]

x_red = [
     date.to_datetime64().astype('M8[ms]').astype('O')
     for date in df_red.index.to_list()
]


#preparing data for each of CDS
data_green= {
    'date':x_green,
    'open':df_green.Open.tolist(),
    'close':df_green.Close.tolist(),
    'y':((df_green.Open + df_green.Close)/2).tolist(),
    'height':((df_green.Close - df_green.Open)).tolist(),
    'low':df_green.Low.tolist(),
    'high':df_green.High.tolist(),
}

data_red= {
    'date':x_red,
    'open':df_red.Open.tolist(),
    'close':df_red.Close.tolist(),
    'y':((df_red.Open + df_red.Close)/2).tolist(),
    'height':((df_red.Close - df_red.Open)).tolist(),
    'low':df_red.Low.tolist(),
    'high':df_red.High.tolist(),
}


source_green=ColumnDataSource(data=data_green)
source_red=ColumnDataSource(data=data_red)

p=figure(x_axis_type="datetime", height=300,sizing_mode="scale_width")
p.title.text = "Candlestick Chart"

hours_12=12*60*60*1000

ciara_green = p.segment(x0="date", y0='low', x1="date", y1='high', color='black', source=source_green)
ciara_red = p.segment(x0="date", y0='low', x1="date", y1='high', color='black', source=source_red)
rect_green = p.rect(x='date',y = 'y', width = hours_12,height = ('height'), fill_color="green", source=source_green)
rect_red = p.rect(x='date',y = 'y', width = hours_12,height = ('height'), fill_color="red", source=source_red)
rect_hover = HoverTool(renderers=[rect_green,rect_red],
                       tooltips=[("Company",name),('Open value','@{open}'),('Close value','@{close}'),('Date','@date{%F}')], formatters={'date':'datetime'})

p.add_tools(rect_hover)

show(p)

Полагаю, есть более элегантный способ сделать это, но это то, что я смог сделать. Помните, большая часть этого кода выполняется из-за HoverTool, который требует ColumnDataSource. В противном случае это легко сделать с помощью pandas dataframe и всего лишь двух (более длинных) строк кода, которые есть в моем первоначальном вопросе. Если вы знакомы с сюжетом: это то же самое, что внедрить функцию наведения в граф? Спасибо

0 голосов
/ 06 апреля 2020

Абсолютно. Позиционные аргументы rect: x, y, width, height, angle и dilate.

Просто создайте источник данных с необходимыми столбцами и передайте имена столбцов вместо ваших данных:

index = df.index[df.Close > df.Open]
close =df.loc[index, 'Close']
open =df.loc[index, 'Open']
cds = ColumnDataSource(dict(x=index, y=(open + close) / 2, width=hours_12, height=(close - open)))
rect1 = p.rect('x', 'y', 'width', 'height', source=cds, fill_color="#CCCCCC", line_color="black")

Обратите внимание, что столбцы могут иметь любые имена. Единственное, что имеет значение, это то, что вы используете одинаковые имена в аргументах rect.

...