Skip to content

Commit dde9e11

Browse files
Merge pull request #530 from DanielGoldfarb/ohlc_v_same_panel
handle OHLC and Volume on same panel
2 parents 5114322 + 5f6f12c commit dde9e11

File tree

3 files changed

+582
-15
lines changed

3 files changed

+582
-15
lines changed

examples/scratch_pad/volume_and_ohlc_same_panel.ipynb

+547
Large diffs are not rendered by default.

src/mplfinance/_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version_info = (0, 12, 9, 'beta', 0)
1+
version_info = (0, 12, 9, 'beta', 1)
22

33
_specifier_ = {'alpha': 'a','beta': 'b','candidate': 'rc','final': ''}
44

src/mplfinance/plotting.py

+34-14
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,16 @@ def _valid_plot_kwargs():
363363
'Description' : 'Volume y-axis scale: "linear", "log", "symlog", or "logit"',
364364
'Validator' : lambda value: _yscale_validator(value) },
365365

366+
'volume_ylim' : { 'Default' : None,
367+
'Description' : 'Volume y-axis limits as tuple (min,max), i.e. (bottom,top)',
368+
'Validator' : lambda value: isinstance(value, (list,tuple)) and len(value) == 2
369+
and all([isinstance(v,(int,float)) for v in value])},
370+
371+
'volume_alpha' : { 'Default' : 1, # alpha of Volume bars
372+
'Description' : 'opacity for Volume bar: 0.0 (transparent) to 1.0 (opaque)',
373+
'Validator' : lambda value: isinstance(value,(int,float)) or
374+
all([isinstance(v,(int,float)) for v in value]) },
375+
366376
'warn_too_much_data' : { 'Default' : 599,
367377
'Description' : 'Tolerance for data amount in plot. Default=599 rows.'+
368378
' Values greater than \'warn_too_much_data\' will trigger a warning.',
@@ -452,13 +462,26 @@ def plot( data, **kwargs ):
452462
raise ValueError('Request for volume, but NO volume data.')
453463

454464
if external_axes_mode:
455-
panels = None
465+
panels = None
466+
axA1 = config['ax']
467+
axA1.set_axisbelow(config['saxbelow'])
456468
if config['volume']:
457469
volumeAxes = config['volume']
458470
volumeAxes.set_axisbelow(config['saxbelow'])
459471
else:
460472
panels = _build_panels(fig, config)
461-
volumeAxes = panels.at[config['volume_panel'],'axes'][0] if config['volume'] is True else None
473+
axA1 = panels.at[config['main_panel'],'axes'][0]
474+
if config['volume']:
475+
if config['volume_panel'] == config['main_panel']:
476+
# ohlc and volume on same panel: move volume to secondary axes:
477+
volumeAxes = panels.at[config['volume_panel'],'axes'][1]
478+
volumeAxes.set_zorder(axA1.get_zorder()-0.1) # Make sure ohlc is above volume
479+
axA1.patch.set_visible(False) # Let volume show through
480+
panels.at[config['main_panel'],'used2nd'] = True
481+
else:
482+
volumeAxes = panels.at[config['volume_panel'],'axes'][0]
483+
else:
484+
volumeAxes = None
462485

463486
fmtstring = _determine_format_string(dates, config['datetime_format'])
464487

@@ -471,20 +494,12 @@ def plot( data, **kwargs ):
471494
formatter = IntegerIndexDateTimeFormatter(dates, fmtstring)
472495
xdates = np.arange(len(dates))
473496

474-
if external_axes_mode:
475-
axA1 = config['ax']
476-
axA1.set_axisbelow(config['saxbelow'])
477-
else:
478-
axA1 = panels.at[config['main_panel'],'axes'][0]
479-
480497
# Will have to handle widths config separately for PMOVE types ??
481498
config['_width_config'] = _determine_width_config(xdates, config)
482499

483-
484500
rwc = config['return_width_config']
485501
if isinstance(rwc,dict) and len(rwc)==0:
486502
config['return_width_config'].update(config['_width_config'])
487-
488503

489504
collections = None
490505
if ptype == 'line':
@@ -621,10 +636,15 @@ def plot( data, **kwargs ):
621636
w = config['_width_config']['volume_width']
622637
lw = config['_width_config']['volume_linewidth']
623638

624-
adjc = _adjust_color_brightness(vcolors,0.90)
625-
volumeAxes.bar(xdates,volumes,width=w,linewidth=lw,color=vcolors,ec=adjc)
626-
vymin = 0.3 * np.nanmin(volumes)
627-
vymax = 1.1 * np.nanmax(volumes)
639+
adjc = _adjust_color_brightness(vcolors,0.90)
640+
valp = config['volume_alpha']
641+
volumeAxes.bar(xdates,volumes,width=w,linewidth=lw,color=vcolors,ec=adjc,alpha=valp)
642+
if config['volume_ylim'] is not None:
643+
vymin = config['volume_ylim'][0]
644+
vymax = config['volume_ylim'][1]
645+
else:
646+
vymin = 0.3 * np.nanmin(volumes)
647+
vymax = 1.1 * np.nanmax(volumes)
628648
volumeAxes.set_ylim(vymin,vymax)
629649

630650
xrotation = config['xrotation']

0 commit comments

Comments
 (0)