1

I have a candlestick chart that works nicely with bokeh. The only issue I have is the data is 1 minute data and chart can look a little squashed together. Is there anyway to create a small gap between the candlestick bars?

update - code

import pandas as pd

from datetime import timedelta

from bokeh.plotting import figure, ColumnDataSource
from bokeh.models.widgets import Dropdown
from bokeh.io import curdoc
from bokeh.layouts import column

from bokeh.models import BooleanFilter, CDSView, Select, Range1d, HoverTool
from bokeh.palettes import Category20
from bokeh.models.formatters import NumeralTickFormatter
from bokeh.io import output_file, show

# Define constants
W_PLOT = 1700
H_PLOT = 600
TOOLS = "pan,box_zoom,zoom_in,zoom_out,redo,undo,reset,save,crosshair"

VBAR_WIDTH = 60*60*10000
# VBAR_WIDTH =  12*60*60*1000 # half day in ms
# VBAR_WIDTH =  24*60*60*1000 # day in ms

RED = Category20[7][6]
GREEN = Category20[5][4]

def plot_test(df: pd.DataFrame,
          name: str) -> None:

inc = df.price_close > df.price_open
dec = ~inc

cds = ColumnDataSource(data=df)   
view_inc = CDSView(source=cds, filters=[BooleanFilter(inc)])
view_dec = CDSView(source=cds, filters=[BooleanFilter(dec)])    

fig = figure(plot_width=W_PLOT, plot_height=H_PLOT, 
             tools=TOOLS,
             x_axis_type="datetime",
             title=name,
             toolbar_location='above')

# Plot candles
# High and low
fig.segment(x0='time_stamp', y0='price_high', 
            x1='time_stamp', y1='price_low', 
            source=cds, view=view_inc, 
            color='black')
fig.segment(x0='time_stamp', y0='price_high', 
            x1='time_stamp', y1='price_low', 
            source=cds, view=view_dec,
            color='black')

# Open and close
r1 = fig.vbar(x='time_stamp', width=timedelta(minutes=1), 
         top='price_open', bottom='price_close', 
              source=cds, view=view_inc,
              fill_color=GREEN, line_color="black")
r2 = fig.vbar(x='time_stamp', width=timedelta(minutes=1), 
         top='price_open', bottom='price_close', 
              source=cds, view=view_dec,
              fill_color=RED, line_color="black")

# let add a moving average
fig.line(x='time_stamp', y='ma_20', source=cds, legend_label='MA 20')

# entry signals
fig.triangle(x='time_stamp', y='buy', source=cds, fill_color=GREEN,
             size=10)
fig.inverted_triangle(x='time_stamp', y='sell', source=cds, 
                      fill_color=RED, size=10)

# Set up the hover tooltip to display some useful data
fig.add_tools(HoverTool(
    renderers=[r1],
    tooltips=[
        ("Open", "@price_open{0.0000}"),
        ("High", "@price_high{0.0000}"),
        ("Low", "@price_low{0.0000}"),
        ("Close", "@price_close{0.0000}"),
        ("Date", "@time_stamp{%Y-%m-%d %H:%M}"),
    ],
    formatters={
        '@time_stamp': 'datetime'
        }))

fig.add_tools(HoverTool(
    renderers=[r2],
    tooltips=[
        ("Open", "@price_open{0.0000}"),
        ("High", "@price_high{0.0000}"),
        ("Low", "@price_low{0.0000}"),
        ("Close", "@price_close{0.0000}"),
        ("Date", "@time_stamp{%Y-%m-%d %H:%M}"),
    ],
    formatters={
        '@time_stamp': 'datetime'
        }))

elements = list()
elements.append(fig)

curdoc().add_root(column(elements))
curdoc.title = 'Blah'

show(fig)
mHelpMe
  • 6,336
  • 24
  • 75
  • 150
  • Please update your post to include a [Minimal Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) that shows what you are starting from / have tried. – bigreddot Apr 02 '21 at 18:58
  • @bigreddot apologies I should have copied my code in the first place, its now in my post – mHelpMe Apr 04 '21 at 09:08
  • Have you tried changing the `width` parameter that you pass to the vbars? Also for the future, you should post the * minimal possible* relevant code. There are dozens of lines about about hover tools, unused imports etc. that have nothing to do with the question and only serve to make it more difficult for anyone to help you . – bigreddot Apr 04 '21 at 19:51
  • Noted for the future. Yes I have tried varies values for the variable VBAR_WIDTH for the width parameter. My understanding for this parameter is that is defines the width of the candlestick. I was looking but couldn't find a parameter where you can specify a gap between candlesticks. For daily data it looks great for minute data it looks very squashed no matter the width I supply – mHelpMe Apr 05 '21 at 09:20
  • What exact values did you try? The values above are all much larger (wider) than one minute. The units of width on a date time axis are milliseconds. – bigreddot Apr 05 '21 at 17:00
  • 1
    Also just to be clear: what determines the width is the value that actual value you pass to the vbar method. You aren't currently passing VBAR_WIDTH either, so it would have no effect. Currently the code above hard codes `width=timedelta(minutes=1)` – bigreddot Apr 05 '21 at 17:03
  • @bigreddot thanks for your help, can't believe I wasn't using the VBAR_WIDTH & yes now I have been able to find the correct value to use for minute data – mHelpMe Apr 05 '21 at 21:28
  • Glad to hear! Please consider self-answering and accepting so that this question has a recorded answer. – bigreddot Apr 05 '21 at 23:04

1 Answers1

1

As pointed out my bigredot, in order to change the width of the candlestick it is done by setting the width parameter of the vbar method.

The number below is good for daily data. For higher frequency data I would reduce the '12'

VBAR_WIDTH = 126060*1000 # half day in ms

mHelpMe
  • 6,336
  • 24
  • 75
  • 150