1

Basically, I'd like to do the same thing as shown in this question, but with two additional modifications:

  • Combine the candlestick and volume into one figure
  • Have two y axes, so that they are scrolled / zoomed independently (e.g. when a candlestick axis is wheel-zoomed, only candlesticks should change in size, not volume bars - and vice-versa for the volume bars)

Is that something that can be done with Bokeh?

levant pied
  • 3,886
  • 5
  • 37
  • 56
  • 1
    Check out the [twin axis example](https://docs.bokeh.org/en/latest/docs/examples/basic/axes/twin_axes.html) the see different options for scrolling. – mosc9575 Jun 29 '23 at 19:29

1 Answers1

3

Yes it is possible to merge the two figures into one. And since bokeh 3.2.0 it is possible to scroll the axis independently. A legend is added to hide the data which is not in your focus as well.

If you don't have the data yet, run this snippet first.

import bokeh
bokeh.sampledata.download()

This is the code to create the figure.

import pandas as pd
import numpy as np
from bokeh.plotting import figure, output_notebook, show
from bokeh.sampledata.stocks import MSFT
from bokeh.models import LinearAxis, Range1d, Segment, Legend
output_notebook()

df = pd.DataFrame(MSFT)[:50]
df["date"] = pd.to_datetime(df["date"])
inc = df.close > df.open
dec = df.open > df.close
w = 12*60*60*1000 # half day in ms

TOOLS = "pan,wheel_zoom,box_zoom,reset,save"
p = figure(
    x_axis_type="datetime",
    tools=TOOLS,
    width=700,
    height=300,
    title = "MSFT Candlestick with Volume"
)
p.add_layout(Legend(click_policy="hide", orientation='horizontal', spacing=20), 'below')
# left y axis
low, high  = df[['open', 'close']].min().min(), df[['open', 'close']].max().max()
diff = high-low
p.y_range = Range1d(low-0.1*diff, high+0.1*diff)
p.yaxis.axis_label = 'Price'
p.segment(df.date, df.high, df.date, df.low, color="black", legend_label='Candlestick')
p.vbar(df.date[inc], w, df.open[inc], df.close[inc], 
       fill_color="#D5E1DD", line_color="black", legend_label='Candlestick')
p.vbar(df.date[dec], w, df.open[dec], df.close[dec], 
       fill_color="#F2583E", line_color="black", legend_label='Candlestick')
# right y axis
p.extra_y_ranges.update({'two':  Range1d(0, 1.1*df.volume.max())})
p.add_layout(LinearAxis(y_range_name='two', axis_label='Volume' ), 'right')
p.vbar(df.date, w, df.volume, [0]*df.shape[0], alpha=0.5, level='underlay', 
       legend_label='Volume', y_range_name='two')
wheel_zoom = p.toolbar.tools[1]
wheel_zoom.zoom_together='none' # can be 'none', 'cross', 'all'
p.toolbar.active_scroll = wheel_zoom
show(p)

The created figure looks like this. stock with two y axis

mosc9575
  • 5,618
  • 2
  • 9
  • 32
  • Do you know if there's a way in Bokeh to allow a user to draw lines with their mouse on the graph from inside the browser? – Jase Jul 08 '21 at 08:02
  • 1
    There is the [FreehandDrawTool](http://docs.bokeh.org/en/latest/docs/user_guide/tools.html#freehanddrawtool) which allows to draw something with the mouse. – mosc9575 Jul 08 '21 at 19:52