Skip to content

Commit b1df20e

Browse files
assorted addplot enhancements in progress
1 parent 2e9d257 commit b1df20e

File tree

3 files changed

+936
-45
lines changed

3 files changed

+936
-45
lines changed

examples/scratch_pad/panels_ylim_width_alpha.ipynb

Lines changed: 849 additions & 0 deletions
Large diffs are not rendered by default.

src/mplfinance/_panels.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def _build_panels( figure, config ):
112112
height=_nones,
113113
used2nd=[False]*len(pset),
114114
title=_nones,
115-
ylabel=_nones),
115+
y_on_right=_nones),
116116
index=pset)
117117
panels.index.name = 'panid'
118118

src/mplfinance/plotting.py

Lines changed: 86 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ def _warn_no_xgaps_deprecated(value):
6767
category=DeprecationWarning)
6868
return isinstance(value,bool)
6969

70+
def _warn_set_ylim_deprecated(value):
71+
warnings.warn('\n\n ================================================================= '+
72+
'\n\n WARNING: `set_ylim=(ymin,ymax)` kwarg '+
73+
'\n has been replaced with: '+
74+
'\n `ylim=(ymin,ymax)`.'+
75+
'\n\n ================================================================ ',
76+
category=DeprecationWarning)
77+
return isinstance(value,bool)
78+
7079

7180
def _valid_plot_kwargs():
7281
'''
@@ -156,16 +165,18 @@ def _valid_plot_kwargs():
156165
'returnfig' : { 'Default' : False,
157166
'Validator' : lambda value: isinstance(value,bool) },
158167

159-
'return_calculated_values' : {'Default': None,
160-
'Validator': lambda value: isinstance(value, dict) and len(value) == 0},
168+
'return_calculated_values' : {'Default' : None,
169+
'Validator' : lambda value: isinstance(value, dict) and len(value) == 0},
161170

162-
'set_ylim' : {'Default': None,
163-
'Validator': lambda value: isinstance(value, (list,tuple)) and len(value) == 2
164-
and all([isinstance(v,(int,float)) for v in value])},
171+
'set_ylim' : {'Default' : None,
172+
'Validator' : lambda value: _warn_set_ylim_deprecated(value) },
173+
174+
'ylim' : {'Default' : None,
175+
'Validator' : lambda value: isinstance(value, (list,tuple)) and len(value) == 2
176+
and all([isinstance(v,(int,float)) for v in value])},
165177

166-
'set_ylim_panelB' : {'Default': None,
167-
'Validator': lambda value: isinstance(value, (list,tuple)) and len(value) == 2
168-
and all([isinstance(v,(int,float)) for v in value])},
178+
'set_ylim_panelB' : {'Default' : None,
179+
'Validator' : lambda value: _warn_set_ylim_deprecated(value) },
169180

170181
'hlines' : { 'Default' : None,
171182
'Validator' : lambda value: _hlines_validator(value) },
@@ -348,8 +359,8 @@ def plot( data, **kwargs ):
348359
miny = np.nanmin(_lows)
349360
maxy = np.nanmax(_highs)
350361

351-
if config['set_ylim'] is not None:
352-
axA1.set_ylim(config['set_ylim'][0], config['set_ylim'][1])
362+
if config['ylim'] is not None:
363+
axA1.set_ylim(config['ylim'][0], config['ylim'][1])
353364
elif config['tight_layout']:
354365
axA1.set_xlim(minx,maxx)
355366
ydelta = 0.01 * (maxy-miny)
@@ -492,8 +503,17 @@ def plot( data, **kwargs ):
492503
#datalim = (minx, min(l)), (maxx, max(h))
493504
#ax.update_datalim(datalim)
494505
ax.autoscale_view()
495-
if (apdict["ylabel"] is not None):
496-
ax.set_ylabel(apdict["ylabel"])
506+
if (apdict['ylabel'] is not None):
507+
ax.set_ylabel(apdict['ylabel'])
508+
if apdict['ylim'] is not None:
509+
ax.set_ylim(apdict['ylim'][0],apdict['ylim'][1])
510+
#elif config['tight_layout']:
511+
# ax.set_xlim(minx,maxx)
512+
# ydelta = 0.01 * (maxy-miny)
513+
# ax.set_ylim(miny-ydelta,maxy+ydelta)
514+
#else:
515+
# corners = (minx, miny), (maxx, maxy)
516+
# ax.update_datalim(corners)
497517
continue
498518

499519
if isinstance(apdata,list) and not isinstance(apdata[0],(float,int)):
@@ -525,33 +545,47 @@ def plot( data, **kwargs ):
525545
else:
526546
ax = panels.at[panid,'axes'][0]
527547

528-
if (apdict["ylabel"] is not None):
529-
ax.set_ylabel(apdict["ylabel"])
530-
531548
aptype = apdict['type']
532549
if aptype == 'scatter':
533550
size = apdict['markersize']
534551
mark = apdict['marker']
535552
color = apdict['color']
553+
alpha = apdict['alpha']
536554
if isinstance(mark,(list,tuple,np.ndarray)):
537-
_mscatter(xdates, ydata, ax=ax, m=mark, s=size, color=color)
555+
_mscatter(xdates,ydata,ax=ax,m=mark,s=size,color=color,alpha=alpha)
538556
else:
539-
ax.scatter(xdates, ydata, s=size, marker=mark, color=color)
557+
ax.scatter(xdates,ydata,s=size,marker=mark,color=color,alpha=alpha)
540558
elif aptype == 'bar':
541-
width = apdict['width']
559+
width = 0.8 if apdict['width'] is None else apdict['width']
542560
bottom = apdict['bottom']
543561
color = apdict['color']
544562
alpha = apdict['alpha']
545-
ax.bar(xdates, ydata, width=width, bottom=bottom, color=color, alpha=alpha)
563+
ax.bar(xdates,ydata,width=width,bottom=bottom,color=color,alpha=alpha)
546564
elif aptype == 'line':
547-
ls = apdict['linestyle']
548-
color = apdict['color']
549-
ax.plot(xdates, ydata, linestyle=ls, color=color)
565+
ls = apdict['linestyle']
566+
color = apdict['color']
567+
width = apdict['width']
568+
alpha = apdict['alpha']
569+
ax.plot(xdates,ydata,linestyle=ls,color=color,linewidth=width,alpha=alpha)
550570
else:
551571
raise ValueError('addplot type "'+str(aptype)+'" NOT yet supported.')
572+
552573
if apdict['mav'] is not None:
553574
apmavprices = _plot_mav(ax,config,xdates,ydata,apdict['mav'])
554575

576+
if (apdict["ylabel"] is not None):
577+
ax.set_ylabel(apdict["ylabel"])
578+
579+
if apdict['ylim'] is not None:
580+
ax.set_ylim(apdict['ylim'][0],apdict['ylim'][1])
581+
#elif config['tight_layout']:
582+
# ax.set_xlim(minx,maxx)
583+
# ydelta = 0.01 * (maxy-miny)
584+
# ax.set_ylim(miny-ydelta,maxy+ydelta)
585+
#else:
586+
# corners = (minx, miny), (maxx, maxy)
587+
# ax.update_datalim(corners)
588+
555589
if config['fill_between'] is not None:
556590
fb = config['fill_between']
557591
panid = config['main_panel']
@@ -567,24 +601,12 @@ def plot( data, **kwargs ):
567601
ax = panels.at[panid,'axes'][0]
568602
ax.fill_between(**fb)
569603

570-
if config['set_ylim_panelB'] is not None:
571-
miny = config['set_ylim_panelB'][0]
572-
maxy = config['set_ylim_panelB'][1]
573-
panels.at[1,'axes'][0].set_ylim( miny, maxy )
574-
575-
# put the twinx() on the "other" side:
576-
if style['y_on_right']:
577-
for ax in panels['axes'].values:
578-
ax[0].yaxis.set_label_position('right')
579-
ax[0].yaxis.tick_right()
580-
ax[1].yaxis.set_label_position('left')
581-
ax[1].yaxis.tick_left()
582-
else:
583-
for ax in panels['axes'].values:
584-
ax[0].yaxis.set_label_position('left')
585-
ax[0].yaxis.tick_left()
586-
ax[1].yaxis.set_label_position('right')
587-
ax[1].yaxis.tick_right()
604+
# put the primary axis on one side,
605+
# and the twinx() on the "other" side:
606+
for panid,row in panels.iterrows():
607+
ax = row['axes']
608+
y_on_right = style['y_on_right'] if row['y_on_right'] is None else row['y_on_right']
609+
_set_ylabels_side(ax[0],ax[1],y_on_right)
588610

589611
# TODO: ================================================================
590612
# TODO: Investigate:
@@ -679,7 +701,23 @@ def plot( data, **kwargs ):
679701
# print('rcpdfhead(3)=',rcpdf.head(3))
680702
# return # rcpdf
681703

682-
def _plot_mav(ax,config,xdates,prices,apmav=None):
704+
def _set_ylabels_side(ax_pri,ax_sec,primary_on_right):
705+
# put the primary axis on one side,
706+
# and the twinx() on the "other" side:
707+
if primary_on_right == True:
708+
ax_pri.yaxis.set_label_position('right')
709+
ax_pri.yaxis.tick_right()
710+
ax_sec.yaxis.set_label_position('left')
711+
ax_sec.yaxis.tick_left()
712+
elif primary_on_right == False:
713+
ax_pri.yaxis.set_label_position('left')
714+
ax_pri.yaxis.tick_left()
715+
ax_sec.yaxis.set_label_position('right')
716+
ax_sec.yaxis.tick_right()
717+
else:
718+
raise ValueError('primary_on_right must be `True` or `False`')
719+
720+
def _plot_mav(ax,config,xdates,prices,apmav=None,apwidth=None):
683721
style = config['style']
684722
if apmav is not None:
685723
mavgs = apmav
@@ -754,14 +792,14 @@ def _valid_addplot_kwargs():
754792
'linestyle' : { 'Default' : None,
755793
'Validator' : lambda value: value in valid_linestyles },
756794

757-
'width' : { 'Default' : 0.8,
795+
'width' : { 'Default' : None, # width of `bar` or `line`
758796
'Validator' : lambda value: isinstance(value,(int,float)) or
759797
all([isinstance(v,(int,float)) for v in value]) },
760798

761-
'bottom' : { 'Default' : 0,
799+
'bottom' : { 'Default' : 0, # bottom for `type=bar` plots
762800
'Validator' : lambda value: isinstance(value,(int,float)) or
763801
all([isinstance(v,(int,float)) for v in value]) },
764-
'alpha' : { 'Default' : 1,
802+
'alpha' : { 'Default' : 1, # alpha of `bar`, `line`, or `scatter`
765803
'Validator' : lambda value: isinstance(value,(int,float)) or
766804
all([isinstance(v,(int,float)) for v in value]) },
767805

@@ -770,6 +808,10 @@ def _valid_addplot_kwargs():
770808

771809
'ylabel' : { 'Default' : None,
772810
'Validator' : lambda value: isinstance(value,str) },
811+
812+
'ylim' : {'Default' : None,
813+
'Validator' : lambda value: isinstance(value, (list,tuple)) and len(value) == 2
814+
and all([isinstance(v,(int,float)) for v in value])},
773815
}
774816

775817
_validate_vkwargs_dict(vkwargs)

0 commit comments

Comments
 (0)