From dc959498ccfed5b4029406598e0feb3cd0da9508 Mon Sep 17 00:00:00 2001 From: lfenzo Date: Fri, 16 Jul 2021 09:51:37 -0300 Subject: [PATCH 01/14] Kwargs for plotting with descriptions and sorted alphabetically --- src/mplfinance/_arg_validators.py | 13 +- src/mplfinance/plotting.py | 442 ++++++++++++++++++------------ 2 files changed, 283 insertions(+), 172 deletions(-) diff --git a/src/mplfinance/_arg_validators.py b/src/mplfinance/_arg_validators.py index ef91eb05..8e6087fa 100644 --- a/src/mplfinance/_arg_validators.py +++ b/src/mplfinance/_arg_validators.py @@ -274,11 +274,16 @@ def _kwarg_not_implemented(value): raise NotImplementedError('kwarg NOT implemented.') def _validate_vkwargs_dict(vkwargs): - # Check that we didn't make a typo in any of the things - # that should be the same for all vkwargs dict items: + """ + Check that we didn't make a typo in any of the things + that should be the same for all vkwargs dict items: + + {kwarg : {'Default': ... , 'Description': ... , 'Validator': ...} } + """ for key, value in vkwargs.items(): - if len(value) != 2: - raise ValueError('Items != 2 in valid kwarg table, for kwarg "'+key+'"') + # has been changed to 3 to support descriptions + if len(value) != 3: + raise ValueError('Items != 3 in valid kwarg table, for kwarg "'+key+'"') if 'Default' not in value: raise ValueError('Missing "Default" value for kwarg "'+key+'"') if 'Validator' not in value: diff --git a/src/mplfinance/plotting.py b/src/mplfinance/plotting.py index c6cccc0b..1801f6f1 100644 --- a/src/mplfinance/plotting.py +++ b/src/mplfinance/plotting.py @@ -21,6 +21,7 @@ from mplfinance._utils import _construct_vline_collections from mplfinance._utils import _construct_tline_collections from mplfinance._utils import _construct_mpf_collections +from mplfinance._utils import _display_formetted_kwargs_table from mplfinance._widths import _determine_width_config @@ -53,6 +54,7 @@ DEFAULT_FIGRATIO = (8.00,5.75) + def with_rc_context(func): ''' This decoractor creates an rcParams context around a function, so that any changes @@ -64,6 +66,7 @@ def decorator(*args, **kwargs): return func(*args, **kwargs) return decorator + def _warn_no_xgaps_deprecated(value): warnings.warn('\n\n ================================================================= '+ '\n\n WARNING: `no_xgaps` is deprecated:'+ @@ -74,6 +77,7 @@ def _warn_no_xgaps_deprecated(value): category=DeprecationWarning) return isinstance(value,bool) + def _warn_set_ylim_deprecated(value): warnings.warn('\n\n ================================================================= '+ '\n\n WARNING: `set_ylim=(ymin,ymax)` kwarg '+ @@ -97,182 +101,257 @@ def _valid_plot_kwargs(): kwarg value is one of the allowed values. ''' + # TODO define where descriptions should be printed: view _utils._display_formetted_kwargs_table() + vkwargs = { - 'columns' : { 'Default' : None, # use default names: ('Open', 'High', 'Low', 'Close', 'Volume') - 'Validator' : lambda value: isinstance(value, (tuple, list)) - and len(value) == 5 - and all(isinstance(c, str) for c in value) }, - 'type' : { 'Default' : 'ohlc', - 'Validator' : lambda value: value in _get_valid_plot_types() }, - - 'style' : { 'Default' : None, - 'Validator' : _styles._valid_mpf_style }, - - 'volume' : { 'Default' : False, - 'Validator' : lambda value: isinstance(value,bool) or isinstance(value,mpl_axes.Axes) }, - - 'mav' : { 'Default' : None, - 'Validator' : _mav_validator }, - - 'renko_params' : { 'Default' : dict(), - 'Validator' : lambda value: isinstance(value,dict) }, + 'addplot' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,dict) + or (isinstance(value,list) + and all([isinstance(d,dict) for d in value])) }, + + 'alines' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: _alines_validator(value) }, - 'pnf_params' : { 'Default' : dict(), - 'Validator' : lambda value: isinstance(value,dict) }, - - 'study' : { 'Default' : None, - 'Validator' : lambda value: _kwarg_not_implemented(value) }, - - 'marketcolors' : { 'Default' : None, # use 'style' for default, instead. - 'Validator' : lambda value: isinstance(value,dict) }, - - 'no_xgaps' : { 'Default' : True, # None means follow default logic below: - 'Validator' : lambda value: _warn_no_xgaps_deprecated(value) }, - - 'show_nontrading' : { 'Default' : False, + 'ax' : { 'Default' : None, + 'Description' : 'Matplotlib ax to be used when plotting.', + 'Validator' : lambda value: isinstance(value,mpl_axes.Axes) }, + + 'axisoff' : { 'Default' : False, + 'Description' : '', 'Validator' : lambda value: isinstance(value,bool) }, - - 'figscale' : { 'Default' : None, # scale base figure size up or down. - 'Validator' : lambda value: isinstance(value,float) or isinstance(value,int) }, - - 'figratio' : { 'Default' : None, # aspect ratio; scaled to 8.0 height + + 'axtitle' : { 'Default' : None, + 'Description' : 'Axes title (subplot title)', + 'Validator' : lambda value: isinstance(value,(str,dict)) }, + + 'block' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,bool) }, + + 'closefig' : { 'Default' : 'auto', + 'Description' : '', + 'Validator' : lambda value: isinstance(value,bool) }, + + 'columns' : { 'Default' : None, + 'Description' : 'Columns to be used when plotting the data. Default: ("Open", "High", "Low", "Close", "Volume")', + 'Validator' : lambda value: isinstance(value, (tuple, list)) + and len(value) == 5 + and all(isinstance(c, str) for c in value) }, + + 'datetime_format' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,str) }, + + 'figratio' : { 'Default' : None, + 'Description' : 'Aspect ratio of the figure, defaults to (0.8)*height.', 'Validator' : lambda value: isinstance(value,(tuple,list)) and len(value) == 2 and isinstance(value[0],(float,int)) and isinstance(value[1],(float,int)) }, - - 'figsize' : { 'Default' : None, # figure size; overrides figratio and figscale + + 'figscale' : { 'Default' : None, # scale base figure size up or down. + 'Description' : '', + 'Validator' : lambda value: isinstance(value,float) + or isinstance(value,int) }, + + 'figsize' : { 'Default' : None, + 'Description' : 'Figure size; overrides figratio and figrate', 'Validator' : lambda value: isinstance(value,(tuple,list)) and len(value) == 2 and isinstance(value[0],(float,int)) and isinstance(value[1],(float,int)) }, - 'fontscale' : { 'Default' : None, # scale all fonts up or down - 'Validator' : lambda value: isinstance(value,float) or isinstance(value,int) }, - - 'linecolor' : { 'Default' : None, # line color in line plot - 'Validator' : lambda value: mcolors.is_color_like(value) }, - - 'title' : { 'Default' : None, # Figure Title - 'Validator' : lambda value: isinstance(value,(str,dict)) }, - - 'axtitle' : { 'Default' : None, # Axes Title (subplot title) - 'Validator' : lambda value: isinstance(value,(str,dict)) }, - - 'ylabel' : { 'Default' : 'Price', # y-axis label - 'Validator' : lambda value: isinstance(value,str) }, - - 'ylabel_lower' : { 'Default' : None, # y-axis label default logic below - 'Validator' : lambda value: isinstance(value,str) }, - - 'addplot' : { 'Default' : None, - 'Validator' : lambda value: isinstance(value,dict) or (isinstance(value,list) and all([isinstance(d,dict) for d in value])) }, - - 'savefig' : { 'Default' : None, - 'Validator' : lambda value: isinstance(value,dict) or isinstance(value,str) or isinstance(value, io.BytesIO) or isinstance(value, os.PathLike) }, - - 'block' : { 'Default' : None, - 'Validator' : lambda value: isinstance(value,bool) }, - - 'returnfig' : { 'Default' : False, - 'Validator' : lambda value: isinstance(value,bool) }, - - 'return_calculated_values' : {'Default' : None, - 'Validator' : lambda value: isinstance(value, dict) and len(value) == 0}, - - 'set_ylim' : {'Default' : None, - 'Validator' : lambda value: _warn_set_ylim_deprecated(value) }, - - 'ylim' : {'Default' : None, - 'Validator' : lambda value: isinstance(value, (list,tuple)) and len(value) == 2 - and all([isinstance(v,(int,float)) for v in value])}, - - 'xlim' : {'Default' : None, - 'Validator' : lambda value: _xlim_validator(value) }, - - 'set_ylim_panelB' : {'Default' : None, - 'Validator' : lambda value: _warn_set_ylim_deprecated(value) }, - - 'hlines' : { 'Default' : None, + 'fill_between' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: _num_or_seq_of_num(value) + or (isinstance(value,dict) + and 'y1' in value + and _num_or_seq_of_num(value['y1'])) }, + + 'fontscale' : { 'Default' : None, + 'Description' : 'Scale all fonts up and down.', + 'Validator' : lambda value: isinstance(value,float) + or isinstance(value,int) }, + + 'hlines' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: _hlines_validator(value) }, - - 'vlines' : { 'Default' : None, - 'Validator' : lambda value: _vlines_validator(value) }, - 'alines' : { 'Default' : None, - 'Validator' : lambda value: _alines_validator(value) }, - - 'tlines' : { 'Default' : None, - 'Validator' : lambda value: _tlines_validator(value) }, - - 'panel_ratios' : { 'Default' : None, - 'Validator' : lambda value: isinstance(value,(tuple,list)) and len(value) <= 10 and - all([isinstance(v,(int,float)) for v in value]) }, + 'linecolor' : { 'Default' : None, + 'Description' : 'Line color in the plot.', + 'Validator' : lambda value: mcolors.is_color_like(value) }, 'main_panel' : { 'Default' : 0, + 'Description' : '', 'Validator' : lambda value: _valid_panel_id(value) }, - 'volume_panel' : { 'Default' : 1, - 'Validator' : lambda value: _valid_panel_id(value) }, + 'marketcolors' : { 'Default' : None, # use 'style' for default, instead. + 'Description' : '', + 'Validator' : lambda value: isinstance(value,dict) }, - 'num_panels' : { 'Default' : None, - 'Validator' : lambda value: isinstance(value,int) and value in range(1,10+1) }, + 'mav' : { 'Default' : None, + 'Description' : 'Moving average window sizes.', + 'Validator' : _mav_validator }, - 'datetime_format' : { 'Default' : None, - 'Validator' : lambda value: isinstance(value,str) }, + 'no_xgaps' : { 'Default' : True, # None means follow default logic below: + 'Description' : '', + 'Validator' : lambda value: _warn_no_xgaps_deprecated(value) }, - 'xrotation' : { 'Default' : 45, - 'Validator' : lambda value: isinstance(value,(int,float)) }, + 'num_panels' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,int) + and value in range(1,10+1) }, - 'axisoff' : { 'Default' : False, - 'Validator' : lambda value: isinstance(value,bool) }, + 'panel_ratios' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,(tuple,list)) + and len(value) <= 10 + and all([isinstance(v,(int,float)) for v in value]) }, - 'closefig' : { 'Default' : 'auto', - 'Validator' : lambda value: isinstance(value,bool) }, + 'pnf_params' : { 'Default' : dict(), + 'Description' : '', + 'Validator' : lambda value: isinstance(value,dict) }, - 'fill_between' : { 'Default' : None, - 'Validator' : lambda value: _num_or_seq_of_num(value) or - (isinstance(value,dict) and 'y1' in value and - _num_or_seq_of_num(value['y1'])) }, + 'renko_params' : { 'Default' : dict(), + 'Description' : '', + 'Validator' : lambda value: isinstance(value,dict) }, - 'tight_layout' : { 'Default' : False, + 'returnfig' : { 'Default' : False, + 'Description' : '', 'Validator' : lambda value: isinstance(value,bool) }, - 'width_adjuster_version' : { 'Default' : 'v1', - 'Validator' : lambda value: value in ('v0', 'v1') }, - - 'scale_width_adjustment' : { 'Default' : None, - 'Validator' : lambda value: isinstance(value,dict) and len(value) > 0 }, - - 'update_width_config' : { 'Default' : None, - 'Validator' : lambda value: isinstance(value,dict) and len(value) > 0 }, + 'return_calculated_values' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value, dict) + and len(value) == 0}, 'return_width_config' : { 'Default' : None, - 'Validator' : lambda value: isinstance(value,dict) and len(value)==0 }, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,dict) + and len(value)==0 }, + + 'savefig' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,dict) + or isinstance(value,str) + or isinstance(value, io.BytesIO) + or isinstance(value, os.PathLike) }, 'saxbelow' : { 'Default' : True, # Issue#115 Comment#639446764 + 'Description' : '', 'Validator' : lambda value: isinstance(value,bool) }, - + + 'scale_width_adjustment' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,dict) + and len(value) > 0 }, + 'scale_padding' : { 'Default' : 1.0, # Issue#193 + 'Description' : '', 'Validator' : lambda value: _scale_padding_validator(value) }, - 'ax' : { 'Default' : None, - 'Validator' : lambda value: isinstance(value,mpl_axes.Axes) }, + 'set_ylim' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: _warn_set_ylim_deprecated(value) }, - 'volume_exponent' : { 'Default' : None, - 'Validator' : lambda value: isinstance(value,int) or value == 'legacy'}, + 'set_ylim_panelB' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: _warn_set_ylim_deprecated(value) }, + + 'show_nontrading' : { 'Default' : False, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,bool) }, + + 'study' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: _kwarg_not_implemented(value) }, + + 'style' : { 'Default' : None, + 'Description' : '', + 'Validator' : _styles._valid_mpf_style }, + + 'tight_layout' : { 'Default' : False, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,bool) }, + + 'title' : { 'Default' : None, + 'Description' : 'Figure title.', + 'Validator' : lambda value: isinstance(value,(str,dict)) }, + + 'tlines' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: _tlines_validator(value) }, + + 'type' : { 'Default' : 'ohlc', + 'Description' : 'Plot type: ohlc, candle, line, renko, pnf', + 'Validator' : lambda value: value in _get_valid_plot_types() }, 'tz_localize' : { 'Default' : True, + 'Description' : '', 'Validator' : lambda value: isinstance(value,bool) }, - 'yscale' : { 'Default' : None, - 'Validator' : lambda value: _yscale_validator(value) }, + 'update_width_config' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,dict) + and len(value) > 0 }, + + 'vlines' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: _vlines_validator(value) }, + + 'volume' : { 'Default' : False, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,bool) + or isinstance(value,mpl_axes.Axes) }, + + 'volume_exponent' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,int) + or value == 'legacy'}, + + 'volume_panel' : { 'Default' : 1, + 'Description' : '', + 'Validator' : lambda value: _valid_panel_id(value) }, 'volume_yscale' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: _yscale_validator(value) }, 'warn_too_much_data' : { 'Default' : 599, + 'Description' : 'Tolerance for data amount in plot. Values greater than \'warn_too_much_data\' will trigger a warning.', 'Validator' : lambda value: isinstance(value,int) }, + + 'width_adjuster_version' : { 'Default' : 'v1', + 'Description' : '', + 'Validator' : lambda value: value in ('v0', 'v1') }, + + 'xlim' : { 'Default' : None, + 'Description' : 'Limits for x axis (left and right).', + 'Validator' : lambda value: _xlim_validator(value) }, + + 'xrotation' : { 'Default' : 45, + 'Description' : 'Angle of rotation (degrees) of ticks in x axis.', + 'Validator' : lambda value: isinstance(value,(int,float)) }, + + 'ylabel' : { 'Default' : 'Price', + 'Description' : 'Y axis label. Default = \'Price\'', + 'Validator' : lambda value: isinstance(value,str) }, + + 'ylabel_lower' : { 'Default' : None, # y-axis label default logic below + 'Description' : '', + 'Validator' : lambda value: isinstance(value,str) }, + + 'ylim' : { 'Default' : None, + 'Description' : 'Limits for y axis (top and bottom).', + 'Validator' : lambda value: isinstance(value, (list,tuple)) + and len(value) == 2 + and all([isinstance(v,(int,float)) for v in value])}, + + 'yscale' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: _yscale_validator(value) }, } _validate_vkwargs_dict(vkwargs) @@ -939,6 +1018,7 @@ def _addplot_columns(panid,panels,ydata,apdict,xdates,config): return ax + def _addplot_apply_supplements(ax,apdict): if (apdict['ylabel'] is not None): ax.set_ylabel(apdict['ylabel']) @@ -954,6 +1034,7 @@ def _addplot_apply_supplements(ax,apdict): elif isinstance(ysd,str): ax.set_yscale(ysd) + def _set_ylabels_side(ax_pri,ax_sec,primary_on_right): # put the primary axis on one side, # and the twinx() on the "other" side: @@ -970,6 +1051,7 @@ def _set_ylabels_side(ax_pri,ax_sec,primary_on_right): ax_sec.yaxis.set_label_position('right') ax_sec.yaxis.tick_right() + def _plot_mav(ax,config,xdates,prices,apmav=None,apwidth=None): style = config['style'] if apmav is not None: @@ -1005,6 +1087,7 @@ def _plot_mav(ax,config,xdates,prices,apmav=None,apwidth=None): mavp_list.append(mavprices) return mavp_list + def _auto_secondary_y( panels, panid, ylo, yhi ): # If mag(nitude) for this panel is not yet set, then set it # here, as this is the first ydata to be plotted on this panel: @@ -1021,6 +1104,7 @@ def _auto_secondary_y( panels, panid, ylo, yhi ): # print('auto says do NOT use secondary_y ... for panel',panid) return secondary_y + def _valid_addplot_kwargs(): valid_linestyles = ('-','solid','--','dashed','-.','dashdot','.','dotted',None,' ','') @@ -1028,66 +1112,88 @@ def _valid_addplot_kwargs(): valid_stepwheres = ('pre','post','mid') vkwargs = { - 'scatter' : { 'Default' : False, - 'Validator' : lambda value: isinstance(value,bool) }, + 'ax' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,mpl_axes.Axes) }, - 'type' : { 'Default' : 'line', - 'Validator' : lambda value: value in valid_types }, + 'alpha' : { 'Default' : 1, # alpha of `bar`, `line`, or `scatter` + 'Description' : '', + 'Validator' : lambda value: isinstance(value,(int,float)) + or all([isinstance(v,(int,float)) for v in value]) }, - 'mav' : { 'Default' : None, - 'Validator' : _mav_validator }, - - 'panel' : { 'Default' : 0, - 'Validator' : lambda value: _valid_panel_id(value) }, + 'bottom' : { 'Default' : 0, # bottom for `type=bar` plots + 'Description' : '', + 'Validator' : lambda value: isinstance(value,(int,float)) + or all([isinstance(v,(int,float)) for v in value]) }, + + 'color' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: mcolors.is_color_like(value) + or (isinstance(value,(list,tuple,np.ndarray)) + and all([mcolors.is_color_like(v) for v in value])) }, + + 'linestyle' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: value in valid_linestyles }, 'marker' : { 'Default' : 'o', - 'Validator' : lambda value: _bypass_kwarg_validation(value) }, + 'Description' : '', + 'Validator' : lambda value: _bypass_kwarg_validation(value) }, 'markersize' : { 'Default' : 18, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(int,float)) }, - 'color' : { 'Default' : None, - 'Validator' : lambda value: mcolors.is_color_like(value) or - (isinstance(value,(list,tuple,np.ndarray)) and all([mcolors.is_color_like(v) for v in value])) }, - - 'linestyle' : { 'Default' : None, - 'Validator' : lambda value: value in valid_linestyles }, + 'mav' : { 'Default' : None, + 'Description' : '', + 'Validator' : _mav_validator }, - 'width' : { 'Default' : None, # width of `bar` or `line` - 'Validator' : lambda value: isinstance(value,(int,float)) or - all([isinstance(v,(int,float)) for v in value]) }, + 'panel' : { 'Default' : 0, + 'Description' : '', + 'Validator' : lambda value: _valid_panel_id(value) }, - 'bottom' : { 'Default' : 0, # bottom for `type=bar` plots - 'Validator' : lambda value: isinstance(value,(int,float)) or - all([isinstance(v,(int,float)) for v in value]) }, - 'alpha' : { 'Default' : 1, # alpha of `bar`, `line`, or `scatter` - 'Validator' : lambda value: isinstance(value,(int,float)) or - all([isinstance(v,(int,float)) for v in value]) }, + 'scatter' : { 'Default' : False, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,bool) }, 'secondary_y' : { 'Default' : 'auto', - 'Validator' : lambda value: isinstance(value,bool) or value == 'auto' }, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,bool) + or value == 'auto' }, + 'stepwhere' : { 'Default' : 'pre', + 'Description' : '', + 'Validator' : lambda value : value in valid_stepwheres }, - 'y_on_right' : { 'Default' : None, - 'Validator' : lambda value: isinstance(value,bool) }, - - 'ylabel' : { 'Default' : None, + 'title' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,str) }, - 'ylim' : {'Default' : None, - 'Validator' : lambda value: isinstance(value, (list,tuple)) and len(value) == 2 - and all([isinstance(v,(int,float)) for v in value])}, + 'type' : { 'Default' : 'line', + 'Description' : '', + 'Validator' : lambda value: value in valid_types }, - 'title' : { 'Default' : None, + 'width' : { 'Default' : None, # width of `bar` or `line` + 'Description' : '', + 'Validator' : lambda value: isinstance(value,(int,float)) + or all([isinstance(v,(int,float)) for v in value]) }, + + 'ylabel' : { 'Default' : None, + 'Description' : 'Label for y axis.', 'Validator' : lambda value: isinstance(value,str) }, - 'ax' : { 'Default' : None, - 'Validator' : lambda value: isinstance(value,mpl_axes.Axes) }, + 'ylim' : { 'Default' : None, + 'Description' : 'Limit values (upper and lower) for the y axis.', + 'Validator' : lambda value: isinstance(value, (list,tuple)) + and len(value) == 2 + and all([isinstance(v,(int,float)) for v in value]) }, 'yscale' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: _yscale_validator(value) }, - 'stepwhere' : { 'Default' : 'pre', - 'Validator' : lambda value : value in valid_stepwheres }, + 'y_on_right' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,bool) }, } _validate_vkwargs_dict(vkwargs) From 4896efacc64bfeb767747b3d96b03a0ee7d7f895 Mon Sep 17 00:00:00 2001 From: lfenzo Date: Fri, 16 Jul 2021 09:57:00 -0300 Subject: [PATCH 02/14] Adding function to display kwarg table with descriptions --- src/mplfinance/_utils.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/mplfinance/_utils.py b/src/mplfinance/_utils.py index e39b6d05..af4f240c 100644 --- a/src/mplfinance/_utils.py +++ b/src/mplfinance/_utils.py @@ -63,6 +63,7 @@ def _check_input(opens, closes, highs, lows): if not same_missing: raise ValueError('O,H,L,C must have the same missing data!') + def _check_and_convert_xlim_configuration(data, config): ''' Check, if user entered `xlim` kwarg, if user entered dates @@ -1391,6 +1392,31 @@ def _tline_lsq(dfslice,tline_use): return _construct_aline_collections(alines, dtix) +def _display_formetted_kwargs_table(kwargs_dict: dict): + """ + Displays through stdout the provided kwargs dict along with each + one of the discriptions and default values. + + Parameters + -------------- + kwargs_dict : dict + Dictionary containing the kwargs in the format (kwarg, default, description) + """ + + # TODO must be defined the best way to place it in the API + # (either inside the 'plot' method or some other auxiliary + # method) + + # prints header of the table + print('=' * 120) + print("{:<30} {:<15} {}".format('kwarg', 'Default', 'Description')) + print('=' * 120) + + for kwarg, info in kwargs_dict.items(): + print(f'{kwarg:30} {str(info["Default"]):15} {info["Description"]}') + print('-' * 120) + + from matplotlib.ticker import Formatter class IntegerIndexDateTimeFormatter(Formatter): """ From 6e6421caf59ee090bcb3f734ca5c4918a93163de Mon Sep 17 00:00:00 2001 From: lfenzo Date: Mon, 19 Jul 2021 13:43:09 -0300 Subject: [PATCH 03/14] Added description fields in remaining kwarg dicts --- TODO.md | 3 +- src/mplfinance/_arg_validators.py | 2 + src/mplfinance/_styles.py | 105 +++++++++++++++++++----------- src/mplfinance/_utils.py | 84 +++++++++++++++++------- src/mplfinance/_widths.py | 20 ++++++ src/mplfinance/plotting.py | 12 ++-- 6 files changed, 158 insertions(+), 68 deletions(-) diff --git a/TODO.md b/TODO.md index 80db8a95..0d0b5bb2 100644 --- a/TODO.md +++ b/TODO.md @@ -9,5 +9,6 @@ - documentation (replace old `https://matplotlib.org/api/finance_api.html`) - make code more efficient (ex: tlines reconstructing data frame). - **daily plot slower than intraday ???** -- add 'description' to valid kwargs table, and kwarg to print all kwargs information (kwarg and short description). +- add kwarg to print all kwargs information (kwarg and short description). +- fill the 'Description' fields in the kwarg dicts of these functions: `egrep -i 'def .*valid.*kwarg' *.py` diff --git a/src/mplfinance/_arg_validators.py b/src/mplfinance/_arg_validators.py index 8e6087fa..97934222 100644 --- a/src/mplfinance/_arg_validators.py +++ b/src/mplfinance/_arg_validators.py @@ -286,6 +286,8 @@ def _validate_vkwargs_dict(vkwargs): raise ValueError('Items != 3 in valid kwarg table, for kwarg "'+key+'"') if 'Default' not in value: raise ValueError('Missing "Default" value for kwarg "'+key+'"') + if 'Description' not in value: + raise ValueError('Missing "Description" value for kwarg "'+key+'"') if 'Validator' not in value: raise ValueError('Missing "Validator" function for kwarg "'+key+'"') diff --git a/src/mplfinance/_styles.py b/src/mplfinance/_styles.py index fde40ae8..316c02e8 100644 --- a/src/mplfinance/_styles.py +++ b/src/mplfinance/_styles.py @@ -61,54 +61,70 @@ def _apply_mpfstyle(style): def _valid_make_mpf_style_kwargs(): vkwargs = { 'base_mpf_style': { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: value in _styles.keys() }, 'base_mpl_style': { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,str) }, # and is in plt.style.available - 'marketcolors' : { 'Default' : None, # + 'marketcolors' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,dict) }, 'mavcolors' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,list) }, # TODO: all([mcolors.is_color_like(v) for v in value.values()]) 'facecolor' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,str) }, 'edgecolor' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,str) }, 'figcolor' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,str) }, 'gridcolor' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,str) }, 'gridstyle' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,str) }, 'gridaxis' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: value in [ 'vertical'[0:len(value)], 'horizontal'[0:len(value)], 'both'[0:len(value)] ] }, 'y_on_right' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,bool) }, 'rc' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,dict) }, 'legacy_rc' : { 'Default' : None, # Just in case someone depended upon old behavior + 'Description' : '', 'Validator' : lambda value: isinstance(value,dict) }, 'style_name' : { 'Default' : None, 'Validator' : lambda value: isinstance(value,str) }, } + _validate_vkwargs_dict(vkwargs) + return vkwargs + def available_styles(): return list(_styles.keys()) - + def make_mpf_style( **kwargs ): config = _process_kwargs(kwargs, _valid_make_mpf_style_kwargs()) if config['rc'] is not None and config['legacy_rc'] is not None: @@ -187,51 +203,66 @@ def _valid_mpf_style(value): return False return True + def _valid_make_marketcolors_kwargs(): vkwargs = { - 'up' : { 'Default' : None, - 'Validator' : lambda value: mcolors.is_color_like(value) }, - - 'down' : { 'Default' : None, - 'Validator' : lambda value: mcolors.is_color_like(value) }, - - 'hollow' : { 'Default' : None, - 'Validator' : lambda value: mcolors.is_color_like(value) }, - - 'alpha' : { 'Default' : None, - 'Validator' : lambda value: ( isinstance(value,float) and - 0.0 <= value and 1.0 >= value ) }, - - 'edge' : { 'Default' : None, - 'Validator' : lambda value: _valid_mpf_color_spec(value) }, - - 'wick' : { 'Default' : None, - 'Validator' : lambda value: isinstance(value,dict) - or isinstance(value,str) - or mcolors.is_color_like(value) }, - - 'ohlc' : { 'Default' : None, - 'Validator' : lambda value: isinstance(value,dict) - or isinstance(value,str) - or mcolors.is_color_like(value) }, - - 'volume' : { 'Default' : None, - 'Validator' : lambda value: isinstance(value,dict) - or isinstance(value,str) - or mcolors.is_color_like(value) }, - - 'vcdopcod' : { 'Default' : False, - 'Validator' : lambda value: isinstance(value,bool) }, + 'up' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: mcolors.is_color_like(value) }, + + 'down' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: mcolors.is_color_like(value) }, + + 'hollow' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: mcolors.is_color_like(value) }, + + 'alpha' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: (isinstance(value,float) + and 0.0 <= value and 1.0 >= value ) }, + + 'edge' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: _valid_mpf_color_spec(value) }, + + 'wick' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,dict) + or isinstance(value,str) + or mcolors.is_color_like(value) }, + + 'ohlc' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,dict) + or isinstance(value,str) + or mcolors.is_color_like(value) }, + + 'volume' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,dict) + or isinstance(value,str) + or mcolors.is_color_like(value) }, + + 'vcdopcod' : { 'Default' : False, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,bool) }, - 'inherit' : { 'Default' : False, - 'Validator' : lambda value: isinstance(value,bool) }, + 'inherit' : { 'Default' : False, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,bool) }, 'base_mpf_style': { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,str) }, } + _validate_vkwargs_dict(vkwargs) + return vkwargs + def make_marketcolors(**kwargs): ''' Create a 'marketcolors' dict that is structured as expected diff --git a/src/mplfinance/_utils.py b/src/mplfinance/_utils.py index af4f240c..cf9777c0 100644 --- a/src/mplfinance/_utils.py +++ b/src/mplfinance/_utils.py @@ -355,9 +355,10 @@ def _valid_renko_kwargs(): ''' Construct and return the "valid renko kwargs table" for the mplfinance.plot(type='renko') function. A valid kwargs table is a `dict` of `dict`s. The keys of the outer dict are - the valid key-words for the function. The value for each key is a dict containing 2 - specific keys: "Default", and "Validator" with the following values: + the valid key-words for the function. The value for each key is a dict containing 3 + specific keys: "Default", "Description" and "Validator" with the following values: "Default" - The default value for the kwarg if none is specified. + "Description" - The description for the kwarg. "Validator" - A function that takes the caller specified value for the kwarg, and validates that it is the correct type, and (for kwargs with a limited set of allowed values) may also validate that the @@ -365,22 +366,28 @@ def _valid_renko_kwargs(): ''' vkwargs = { 'brick_size' : { 'Default' : 'atr', - 'Validator' : lambda value: isinstance(value,(float,int)) or value == 'atr' }, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,(float,int)) + or value == 'atr' }, 'atr_length' : { 'Default' : 14, - 'Validator' : lambda value: isinstance(value,int) or value == 'total' }, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,int) + or value == 'total' }, } _validate_vkwargs_dict(vkwargs) return vkwargs + def _valid_pnf_kwargs(): ''' Construct and return the "valid pnf kwargs table" for the mplfinance.plot(type='pnf') function. A valid kwargs table is a `dict` of `dict`s. The keys of the outer dict are - the valid key-words for the function. The value for each key is a dict containing 2 - specific keys: "Default", and "Validator" with the following values: + the valid key-words for the function. The value for each key is a dict containing 3 + specific keys: "Default", "Description" and "Validator" with the following values: "Default" - The default value for the kwarg if none is specified. + "Description" - The description for the kwarg. "Validator" - A function that takes the caller specified value for the kwarg, and validates that it is the correct type, and (for kwargs with a limited set of allowed values) may also validate that the @@ -388,25 +395,33 @@ def _valid_pnf_kwargs(): ''' vkwargs = { 'box_size' : { 'Default' : 'atr', - 'Validator' : lambda value: isinstance(value,(float,int)) or value == 'atr' }, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,(float,int)) + or value == 'atr' }, 'atr_length' : { 'Default' : 14, - 'Validator' : lambda value: isinstance(value,int) or value == 'total' }, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,int) + or value == 'total' }, + 'reversal' : { 'Default' : 1, - 'Validator' : lambda value: isinstance(value,int) } + 'Description' : '', + 'Validator' : lambda value: isinstance(value,int) }, } _validate_vkwargs_dict(vkwargs) return vkwargs + def _valid_lines_kwargs(): ''' Construct and return the "valid lines (hlines,vlines,alines,tlines) kwargs table" for the mplfinance.plot() `[h|v|a|t]lines=` kwarg functions. A valid kwargs table is a `dict` of `dict`s. The keys of the outer dict are - the valid key-words for the function. The value for each key is a dict containing 2 - specific keys: "Default", and "Validator" with the following values: + the valid key-words for the function. The value for each key is a dict containing 3 + specific keys: "Default", "Description" and "Validator" with the following values: "Default" - The default value for the kwarg if none is specified. + "Description" - The description for the kwarg. "Validator" - A function that takes the caller specified value for the kwarg, and validates that it is the correct type, and (for kwargs with a limited set of allowed values) may also validate that the @@ -415,32 +430,53 @@ def _valid_lines_kwargs(): valid_linestyles = ['-','solid','--','dashed','-.','dashdot',':','dotted',None,' ',''] vkwargs = { 'hlines' : { 'Default' : None, + 'Description' : '', 'Validator' : _bypass_kwarg_validation }, + 'vlines' : { 'Default' : None, + 'Description' : '', 'Validator' : _bypass_kwarg_validation }, + 'alines' : { 'Default' : None, + 'Description' : '', 'Validator' : _bypass_kwarg_validation }, + 'tlines' : { 'Default' : None, + 'Description' : '', 'Validator' : _bypass_kwarg_validation }, + 'colors' : { 'Default' : None, - 'Validator' : lambda value: value is None or - mcolors.is_color_like(value) or - ( isinstance(value,(list,tuple)) and - all([mcolors.is_color_like(v) for v in value]) ) }, + 'Description' : '', + 'Validator' : lambda value: value is None + or mcolors.is_color_like(value) + or (isinstance(value,(list,tuple)) + and all([mcolors.is_color_like(v) for v in value]) ) }, + 'linestyle' : { 'Default' : '-', - 'Validator' : lambda value: value is None or value in valid_linestyles }, + 'Description' : '', + 'Validator' : lambda value: value is None + or value in valid_linestyles }, + 'linewidths': { 'Default' : None, - 'Validator' : lambda value: value is None or - isinstance(value,(float,int)) or - all([isinstance(v,(float,int)) for v in value]) }, + 'Description' : '', + 'Validator' : lambda value: value is None + or isinstance(value,(float,int)) + or all([isinstance(v,(float,int)) for v in value]) }, + 'alpha' : { 'Default' : 1.0, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, - 'tline_use' : { 'Default' : 'close', - 'Validator' : lambda value: isinstance(value,str) or (isinstance(value,(list,tuple)) and - all([isinstance(v,str) for v in value]) ) }, - 'tline_method': { 'Default' : 'point-to-point', - 'Validator' : lambda value: value in ['point-to-point','least-squares'] } + + 'tline_use' : { 'Default' : 'close', + 'Description' : '', + 'Validator' : lambda value: isinstance(value,str) + or (isinstance(value,(list,tuple)) + and all([isinstance(v,str) for v in value]) ) }, + + 'tline_method': { 'Default' : 'point-to-point', + 'Description' : '', + 'Validator' : lambda value: value in ['point-to-point','least-squares'] } } _validate_vkwargs_dict(vkwargs) diff --git a/src/mplfinance/_widths.py b/src/mplfinance/_widths.py index 1cc4aefe..a608fbba 100644 --- a/src/mplfinance/_widths.py +++ b/src/mplfinance/_widths.py @@ -29,57 +29,77 @@ def _get_widths_df(): _widths = _get_widths_df() + def _valid_scale_width_kwargs(): vkwargs = { 'ohlc' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'volume' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'candle' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'lines' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'volume_linewidth' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'ohlc_linewidth' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'candle_linewidth' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, } + _validate_vkwargs_dict(vkwargs) + return vkwargs + def _valid_update_width_kwargs(): vkwargs = { 'ohlc_ticksize' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'ohlc_linewidth' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'volume_width' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'volume_linewidth' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'candle_width' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'candle_linewidth' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'line_width' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, } + _validate_vkwargs_dict(vkwargs) + return vkwargs diff --git a/src/mplfinance/plotting.py b/src/mplfinance/plotting.py index 1801f6f1..8da3694b 100644 --- a/src/mplfinance/plotting.py +++ b/src/mplfinance/plotting.py @@ -152,7 +152,7 @@ def _valid_plot_kwargs(): and isinstance(value[1],(float,int)) }, 'figscale' : { 'Default' : None, # scale base figure size up or down. - 'Description' : '', + 'Description' : 'Scale base figure up and down.', 'Validator' : lambda value: isinstance(value,float) or isinstance(value,int) }, @@ -1122,7 +1122,7 @@ def _valid_addplot_kwargs(): or all([isinstance(v,(int,float)) for v in value]) }, 'bottom' : { 'Default' : 0, # bottom for `type=bar` plots - 'Description' : '', + 'Description' : 'Bottom for ', 'Validator' : lambda value: isinstance(value,(int,float)) or all([isinstance(v,(int,float)) for v in value]) }, @@ -1137,18 +1137,18 @@ def _valid_addplot_kwargs(): 'Validator' : lambda value: value in valid_linestyles }, 'marker' : { 'Default' : 'o', - 'Description' : '', + 'Description' : 'Marker style', 'Validator' : lambda value: _bypass_kwarg_validation(value) }, 'markersize' : { 'Default' : 18, - 'Description' : '', + 'Description' : 'Size of marker.', 'Validator' : lambda value: isinstance(value,(int,float)) }, 'mav' : { 'Default' : None, 'Description' : '', 'Validator' : _mav_validator }, - 'panel' : { 'Default' : 0, + 'panel' : { 'Default' : 0, 'Description' : '', 'Validator' : lambda value: _valid_panel_id(value) }, @@ -1162,7 +1162,7 @@ def _valid_addplot_kwargs(): or value == 'auto' }, 'stepwhere' : { 'Default' : 'pre', 'Description' : '', - 'Validator' : lambda value : value in valid_stepwheres }, + 'Validator' : lambda value : value in valid_stepwheres }, 'title' : { 'Default' : None, 'Description' : '', From b68230d715495e4e46ec992ce728077344a65996 Mon Sep 17 00:00:00 2001 From: Daniel Goldfarb Date: Tue, 28 Dec 2021 13:28:25 -0500 Subject: [PATCH 04/14] kwargs back in original order; tweak descriptions --- src/mplfinance/plotting.py | 439 +++++++++++++++++-------------------- 1 file changed, 205 insertions(+), 234 deletions(-) diff --git a/src/mplfinance/plotting.py b/src/mplfinance/plotting.py index 8da3694b..2e20381a 100644 --- a/src/mplfinance/plotting.py +++ b/src/mplfinance/plotting.py @@ -21,7 +21,6 @@ from mplfinance._utils import _construct_vline_collections from mplfinance._utils import _construct_tline_collections from mplfinance._utils import _construct_mpf_collections -from mplfinance._utils import _display_formetted_kwargs_table from mplfinance._widths import _determine_width_config @@ -54,7 +53,6 @@ DEFAULT_FIGRATIO = (8.00,5.75) - def with_rc_context(func): ''' This decoractor creates an rcParams context around a function, so that any changes @@ -66,7 +64,6 @@ def decorator(*args, **kwargs): return func(*args, **kwargs) return decorator - def _warn_no_xgaps_deprecated(value): warnings.warn('\n\n ================================================================= '+ '\n\n WARNING: `no_xgaps` is deprecated:'+ @@ -77,7 +74,6 @@ def _warn_no_xgaps_deprecated(value): category=DeprecationWarning) return isinstance(value,bool) - def _warn_set_ylim_deprecated(value): warnings.warn('\n\n ================================================================= '+ '\n\n WARNING: `set_ylim=(ymin,ymax)` kwarg '+ @@ -101,257 +97,240 @@ def _valid_plot_kwargs(): kwarg value is one of the allowed values. ''' - # TODO define where descriptions should be printed: view _utils._display_formetted_kwargs_table() - vkwargs = { - 'addplot' : { 'Default' : None, + 'columns' : { 'Default' : None, # use default names: ('Open', 'High', 'Low', 'Close', 'Volume') + 'Description' : ('Column names to be used when plotting the data.'+ + ' Default: ("Open", "High", "Low", "Close", "Volume")'), + 'Validator' : lambda value: isinstance(value, (tuple, list)) + and len(value) == 5 + and all(isinstance(c, str) for c in value) }, + 'type' : { 'Default' : 'ohlc', + 'Description' : 'Plot type: '+str(_get_valid_plot_types()), + 'Validator' : lambda value: value in _get_valid_plot_types() }, + + 'style' : { 'Default' : None, + 'Description' : 'plot style; see `mpf.available_styles()`', + 'Validator' : _styles._valid_mpf_style }, + + 'volume' : { 'Default' : False, + 'Description' : 'Plot volume: True, False, or set to Axes object on which to plot.', + 'Validator' : lambda value: isinstance(value,bool) or isinstance(value,mpl_axes.Axes) }, + + 'mav' : { 'Default' : None, + 'Description' : 'Moving Average window size(s); (int or tuple of ints)', + 'Validator' : _mav_validator }, + + 'renko_params' : { 'Default' : dict(), 'Description' : '', - 'Validator' : lambda value: isinstance(value,dict) - or (isinstance(value,list) - and all([isinstance(d,dict) for d in value])) }, + 'Validator' : lambda value: isinstance(value,dict) }, - 'alines' : { 'Default' : None, + 'pnf_params' : { 'Default' : dict(), 'Description' : '', - 'Validator' : lambda value: _alines_validator(value) }, - - 'ax' : { 'Default' : None, - 'Description' : 'Matplotlib ax to be used when plotting.', - 'Validator' : lambda value: isinstance(value,mpl_axes.Axes) }, - - 'axisoff' : { 'Default' : False, + 'Validator' : lambda value: isinstance(value,dict) }, + + 'study' : { 'Default' : None, 'Description' : '', - 'Validator' : lambda value: isinstance(value,bool) }, - - 'axtitle' : { 'Default' : None, - 'Description' : 'Axes title (subplot title)', - 'Validator' : lambda value: isinstance(value,(str,dict)) }, - - 'block' : { 'Default' : None, + 'Validator' : lambda value: _kwarg_not_implemented(value) }, + + 'marketcolors' : { 'Default' : None, # use 'style' for default, instead. 'Description' : '', - 'Validator' : lambda value: isinstance(value,bool) }, - - 'closefig' : { 'Default' : 'auto', + 'Validator' : lambda value: isinstance(value,dict) }, + + 'no_xgaps' : { 'Default' : True, # None means follow default logic below: 'Description' : '', - 'Validator' : lambda value: isinstance(value,bool) }, - - 'columns' : { 'Default' : None, - 'Description' : 'Columns to be used when plotting the data. Default: ("Open", "High", "Low", "Close", "Volume")', - 'Validator' : lambda value: isinstance(value, (tuple, list)) - and len(value) == 5 - and all(isinstance(c, str) for c in value) }, - - 'datetime_format' : { 'Default' : None, + 'Validator' : lambda value: _warn_no_xgaps_deprecated(value) }, + + 'show_nontrading' : { 'Default' : False, 'Description' : '', - 'Validator' : lambda value: isinstance(value,str) }, - - 'figratio' : { 'Default' : None, - 'Description' : 'Aspect ratio of the figure, defaults to (0.8)*height.', + 'Validator' : lambda value: isinstance(value,bool) }, + + 'figscale' : { 'Default' : None, # scale base figure size up or down. + 'Description' : 'Scale figure size up (if > 1) or down (if < 1)', + 'Validator' : lambda value: isinstance(value,float) or isinstance(value,int) }, + + 'figratio' : { 'Default' : None, # aspect ratio; scaled to 8.0 height + 'Description' : 'Aspect ratio of the figure. Default: (8.00,5.75)', 'Validator' : lambda value: isinstance(value,(tuple,list)) and len(value) == 2 and isinstance(value[0],(float,int)) and isinstance(value[1],(float,int)) }, - - 'figscale' : { 'Default' : None, # scale base figure size up or down. - 'Description' : 'Scale base figure up and down.', - 'Validator' : lambda value: isinstance(value,float) - or isinstance(value,int) }, - - 'figsize' : { 'Default' : None, - 'Description' : 'Figure size; overrides figratio and figrate', + + 'figsize' : { 'Default' : None, # figure size; overrides figratio and figscale + 'Description' : ('Figure size: overrides both figscale and figratio,'+ + ' else defaults to figratio*figscale'), 'Validator' : lambda value: isinstance(value,(tuple,list)) and len(value) == 2 and isinstance(value[0],(float,int)) and isinstance(value[1],(float,int)) }, - 'fill_between' : { 'Default' : None, - 'Description' : '', - 'Validator' : lambda value: _num_or_seq_of_num(value) - or (isinstance(value,dict) - and 'y1' in value - and _num_or_seq_of_num(value['y1'])) }, - - 'fontscale' : { 'Default' : None, - 'Description' : 'Scale all fonts up and down.', - 'Validator' : lambda value: isinstance(value,float) - or isinstance(value,int) }, - - 'hlines' : { 'Default' : None, - 'Description' : '', - 'Validator' : lambda value: _hlines_validator(value) }, - - 'linecolor' : { 'Default' : None, - 'Description' : 'Line color in the plot.', + 'fontscale' : { 'Default' : None, # scale all fonts up or down + 'Description' : 'Scale font sizes up (if > 1) or down (if < 1)', + 'Validator' : lambda value: isinstance(value,float) or isinstance(value,int) }, + + 'linecolor' : { 'Default' : None, # line color in line plot + 'Description' : 'Line color for `type=line`', 'Validator' : lambda value: mcolors.is_color_like(value) }, - 'main_panel' : { 'Default' : 0, + 'title' : { 'Default' : None, # Figure Title + 'Description' : 'Figure Title (see also `axtitle`)', + 'Validator' : lambda value: isinstance(value,(str,dict)) }, + + 'axtitle' : { 'Default' : None, # Axes Title (subplot title) + 'Description' : 'Axes Title (subplot title)', + 'Validator' : lambda value: isinstance(value,(str,dict)) }, + + 'ylabel' : { 'Default' : 'Price', # y-axis label 'Description' : '', - 'Validator' : lambda value: _valid_panel_id(value) }, - - 'marketcolors' : { 'Default' : None, # use 'style' for default, instead. + 'Validator' : lambda value: isinstance(value,str) }, + + 'ylabel_lower' : { 'Default' : None, # y-axis label default logic below 'Description' : '', - 'Validator' : lambda value: isinstance(value,dict) }, - - 'mav' : { 'Default' : None, - 'Description' : 'Moving average window sizes.', - 'Validator' : _mav_validator }, - - 'no_xgaps' : { 'Default' : True, # None means follow default logic below: + 'Validator' : lambda value: isinstance(value,str) }, + + 'addplot' : { 'Default' : None, 'Description' : '', - 'Validator' : lambda value: _warn_no_xgaps_deprecated(value) }, - - 'num_panels' : { 'Default' : None, + 'Validator' : lambda value: isinstance(value,dict) or (isinstance(value,list) and all([isinstance(d,dict) for d in value])) }, + + 'savefig' : { 'Default' : None, 'Description' : '', - 'Validator' : lambda value: isinstance(value,int) - and value in range(1,10+1) }, - - 'panel_ratios' : { 'Default' : None, + 'Validator' : lambda value: isinstance(value,dict) or isinstance(value,str) or isinstance(value, io.BytesIO) or isinstance(value, os.PathLike) }, + + 'block' : { 'Default' : None, 'Description' : '', - 'Validator' : lambda value: isinstance(value,(tuple,list)) - and len(value) <= 10 - and all([isinstance(v,(int,float)) for v in value]) }, - - 'pnf_params' : { 'Default' : dict(), + 'Validator' : lambda value: isinstance(value,bool) }, + + 'returnfig' : { 'Default' : False, 'Description' : '', - 'Validator' : lambda value: isinstance(value,dict) }, + 'Validator' : lambda value: isinstance(value,bool) }, - 'renko_params' : { 'Default' : dict(), + 'return_calculated_values' : { 'Default' : None, 'Description' : '', - 'Validator' : lambda value: isinstance(value,dict) }, + 'Validator' : lambda value: isinstance(value, dict) and len(value) == 0}, - 'returnfig' : { 'Default' : False, + 'set_ylim' : { 'Default' : None, 'Description' : '', - 'Validator' : lambda value: isinstance(value,bool) }, - - 'return_calculated_values' : { 'Default' : None, + 'Validator' : lambda value: _warn_set_ylim_deprecated(value) }, + + 'ylim' : { 'Default' : None, + 'Description' : 'Limits for y-axis as tuple (min,max), i.e. (bottom,top)', + 'Validator' : lambda value: isinstance(value, (list,tuple)) and len(value) == 2 + and all([isinstance(v,(int,float)) for v in value])}, + + 'xlim' : { 'Default' : None, + 'Description' : 'Limits for x-axis as tuple (min, max), i.e. (left,right)', + 'Validator' : lambda value: _xlim_validator(value) }, + + 'set_ylim_panelB' : { 'Default' : None, 'Description' : '', - 'Validator' : lambda value: isinstance(value, dict) - and len(value) == 0}, - - 'return_width_config' : { 'Default' : None, + 'Validator' : lambda value: _warn_set_ylim_deprecated(value) }, + + 'hlines' : { 'Default' : None, 'Description' : '', - 'Validator' : lambda value: isinstance(value,dict) - and len(value)==0 }, - - 'savefig' : { 'Default' : None, + 'Validator' : lambda value: _hlines_validator(value) }, + + 'vlines' : { 'Default' : None, 'Description' : '', - 'Validator' : lambda value: isinstance(value,dict) - or isinstance(value,str) - or isinstance(value, io.BytesIO) - or isinstance(value, os.PathLike) }, + 'Validator' : lambda value: _vlines_validator(value) }, - 'saxbelow' : { 'Default' : True, # Issue#115 Comment#639446764 + 'alines' : { 'Default' : None, 'Description' : '', - 'Validator' : lambda value: isinstance(value,bool) }, - - 'scale_width_adjustment' : { 'Default' : None, + 'Validator' : lambda value: _alines_validator(value) }, + + 'tlines' : { 'Default' : None, 'Description' : '', - 'Validator' : lambda value: isinstance(value,dict) - and len(value) > 0 }, + 'Validator' : lambda value: _tlines_validator(value) }, + + 'panel_ratios' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,(tuple,list)) and len(value) <= 10 and + all([isinstance(v,(int,float)) for v in value]) }, - 'scale_padding' : { 'Default' : 1.0, # Issue#193 + 'main_panel' : { 'Default' : 0, 'Description' : '', - 'Validator' : lambda value: _scale_padding_validator(value) }, + 'Validator' : lambda value: _valid_panel_id(value) }, - 'set_ylim' : { 'Default' : None, + 'volume_panel' : { 'Default' : 1, 'Description' : '', - 'Validator' : lambda value: _warn_set_ylim_deprecated(value) }, + 'Validator' : lambda value: _valid_panel_id(value) }, - 'set_ylim_panelB' : { 'Default' : None, + 'num_panels' : { 'Default' : None, 'Description' : '', - 'Validator' : lambda value: _warn_set_ylim_deprecated(value) }, + 'Validator' : lambda value: isinstance(value,int) and value in range(1,10+1) }, - 'show_nontrading' : { 'Default' : False, + 'datetime_format' : { 'Default' : None, 'Description' : '', + 'Validator' : lambda value: isinstance(value,str) }, + + 'xrotation' : { 'Default' : 45, + 'Description' : 'Angle (degrees) for x-axis tick labels; 90=vertical', + 'Validator' : lambda value: isinstance(value,(int,float)) }, + + 'axisoff' : { 'Default' : False, + 'Description' : '`axisoff=True` means do NOT display any axis.', 'Validator' : lambda value: isinstance(value,bool) }, - 'study' : { 'Default' : None, + 'closefig' : { 'Default' : 'auto', 'Description' : '', - 'Validator' : lambda value: _kwarg_not_implemented(value) }, + 'Validator' : lambda value: isinstance(value,bool) }, - 'style' : { 'Default' : None, + 'fill_between' : { 'Default' : None, 'Description' : '', - 'Validator' : _styles._valid_mpf_style }, + 'Validator' : lambda value: _num_or_seq_of_num(value) or + (isinstance(value,dict) and 'y1' in value and + _num_or_seq_of_num(value['y1'])) }, 'tight_layout' : { 'Default' : False, 'Description' : '', 'Validator' : lambda value: isinstance(value,bool) }, - 'title' : { 'Default' : None, - 'Description' : 'Figure title.', - 'Validator' : lambda value: isinstance(value,(str,dict)) }, - - 'tlines' : { 'Default' : None, + 'width_adjuster_version' : { 'Default' : 'v1', 'Description' : '', - 'Validator' : lambda value: _tlines_validator(value) }, - - 'type' : { 'Default' : 'ohlc', - 'Description' : 'Plot type: ohlc, candle, line, renko, pnf', - 'Validator' : lambda value: value in _get_valid_plot_types() }, + 'Validator' : lambda value: value in ('v0', 'v1') }, - 'tz_localize' : { 'Default' : True, + 'scale_width_adjustment' : { 'Default' : None, 'Description' : '', - 'Validator' : lambda value: isinstance(value,bool) }, + 'Validator' : lambda value: isinstance(value,dict) and len(value) > 0 }, 'update_width_config' : { 'Default' : None, 'Description' : '', - 'Validator' : lambda value: isinstance(value,dict) - and len(value) > 0 }, + 'Validator' : lambda value: isinstance(value,dict) and len(value) > 0 }, - 'vlines' : { 'Default' : None, + 'return_width_config' : { 'Default' : None, 'Description' : '', - 'Validator' : lambda value: _vlines_validator(value) }, + 'Validator' : lambda value: isinstance(value,dict) and len(value)==0 }, - 'volume' : { 'Default' : False, + 'saxbelow' : { 'Default' : True, # Issue#115 Comment#639446764 'Description' : '', - 'Validator' : lambda value: isinstance(value,bool) - or isinstance(value,mpl_axes.Axes) }, + 'Validator' : lambda value: isinstance(value,bool) }, + + 'scale_padding' : { 'Default' : 1.0, # Issue#193 + 'Description' : '', + 'Validator' : lambda value: _scale_padding_validator(value) }, + + 'ax' : { 'Default' : None, + 'Description' : 'Matplotlib Axes object on which to plot', + 'Validator' : lambda value: isinstance(value,mpl_axes.Axes) }, 'volume_exponent' : { 'Default' : None, 'Description' : '', - 'Validator' : lambda value: isinstance(value,int) - or value == 'legacy'}, + 'Validator' : lambda value: isinstance(value,int) or value == 'legacy'}, - 'volume_panel' : { 'Default' : 1, + 'tz_localize' : { 'Default' : True, 'Description' : '', - 'Validator' : lambda value: _valid_panel_id(value) }, + 'Validator' : lambda value: isinstance(value,bool) }, + + 'yscale' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: _yscale_validator(value) }, 'volume_yscale' : { 'Default' : None, 'Description' : '', 'Validator' : lambda value: _yscale_validator(value) }, 'warn_too_much_data' : { 'Default' : 599, - 'Description' : 'Tolerance for data amount in plot. Values greater than \'warn_too_much_data\' will trigger a warning.', + 'Description' : ('Tolerance for data amount in plot. Default=599 rows.'+ + ' Values greater than \'warn_too_much_data\' will trigger a warning.'), 'Validator' : lambda value: isinstance(value,int) }, - - 'width_adjuster_version' : { 'Default' : 'v1', - 'Description' : '', - 'Validator' : lambda value: value in ('v0', 'v1') }, - - 'xlim' : { 'Default' : None, - 'Description' : 'Limits for x axis (left and right).', - 'Validator' : lambda value: _xlim_validator(value) }, - - 'xrotation' : { 'Default' : 45, - 'Description' : 'Angle of rotation (degrees) of ticks in x axis.', - 'Validator' : lambda value: isinstance(value,(int,float)) }, - - 'ylabel' : { 'Default' : 'Price', - 'Description' : 'Y axis label. Default = \'Price\'', - 'Validator' : lambda value: isinstance(value,str) }, - - 'ylabel_lower' : { 'Default' : None, # y-axis label default logic below - 'Description' : '', - 'Validator' : lambda value: isinstance(value,str) }, - - 'ylim' : { 'Default' : None, - 'Description' : 'Limits for y axis (top and bottom).', - 'Validator' : lambda value: isinstance(value, (list,tuple)) - and len(value) == 2 - and all([isinstance(v,(int,float)) for v in value])}, - - 'yscale' : { 'Default' : None, - 'Description' : '', - 'Validator' : lambda value: _yscale_validator(value) }, } _validate_vkwargs_dict(vkwargs) @@ -1018,7 +997,6 @@ def _addplot_columns(panid,panels,ydata,apdict,xdates,config): return ax - def _addplot_apply_supplements(ax,apdict): if (apdict['ylabel'] is not None): ax.set_ylabel(apdict['ylabel']) @@ -1034,7 +1012,6 @@ def _addplot_apply_supplements(ax,apdict): elif isinstance(ysd,str): ax.set_yscale(ysd) - def _set_ylabels_side(ax_pri,ax_sec,primary_on_right): # put the primary axis on one side, # and the twinx() on the "other" side: @@ -1051,7 +1028,6 @@ def _set_ylabels_side(ax_pri,ax_sec,primary_on_right): ax_sec.yaxis.set_label_position('right') ax_sec.yaxis.tick_right() - def _plot_mav(ax,config,xdates,prices,apmav=None,apwidth=None): style = config['style'] if apmav is not None: @@ -1087,7 +1063,6 @@ def _plot_mav(ax,config,xdates,prices,apmav=None,apwidth=None): mavp_list.append(mavprices) return mavp_list - def _auto_secondary_y( panels, panid, ylo, yhi ): # If mag(nitude) for this panel is not yet set, then set it # here, as this is the first ydata to be plotted on this panel: @@ -1104,7 +1079,6 @@ def _auto_secondary_y( panels, panid, ylo, yhi ): # print('auto says do NOT use secondary_y ... for panel',panid) return secondary_y - def _valid_addplot_kwargs(): valid_linestyles = ('-','solid','--','dashed','-.','dashdot','.','dotted',None,' ','') @@ -1112,88 +1086,85 @@ def _valid_addplot_kwargs(): valid_stepwheres = ('pre','post','mid') vkwargs = { - 'ax' : { 'Default' : None, + 'scatter' : { 'Default' : False, 'Description' : '', - 'Validator' : lambda value: isinstance(value,mpl_axes.Axes) }, + 'Validator' : lambda value: isinstance(value,bool) }, - 'alpha' : { 'Default' : 1, # alpha of `bar`, `line`, or `scatter` + 'type' : { 'Default' : 'line', 'Description' : '', - 'Validator' : lambda value: isinstance(value,(int,float)) - or all([isinstance(v,(int,float)) for v in value]) }, - - 'bottom' : { 'Default' : 0, # bottom for `type=bar` plots - 'Description' : 'Bottom for ', - 'Validator' : lambda value: isinstance(value,(int,float)) - or all([isinstance(v,(int,float)) for v in value]) }, + 'Validator' : lambda value: value in valid_types }, - 'color' : { 'Default' : None, + 'mav' : { 'Default' : None, 'Description' : '', - 'Validator' : lambda value: mcolors.is_color_like(value) - or (isinstance(value,(list,tuple,np.ndarray)) - and all([mcolors.is_color_like(v) for v in value])) }, - - 'linestyle' : { 'Default' : None, + 'Validator' : _mav_validator }, + + 'panel' : { 'Default' : 0, 'Description' : '', - 'Validator' : lambda value: value in valid_linestyles }, + 'Validator' : lambda value: _valid_panel_id(value) }, 'marker' : { 'Default' : 'o', - 'Description' : 'Marker style', - 'Validator' : lambda value: _bypass_kwarg_validation(value) }, + 'Description' : '', + 'Validator' : lambda value: _bypass_kwarg_validation(value) }, 'markersize' : { 'Default' : 18, - 'Description' : 'Size of marker.', + 'Description' : 'size of marker for `type=scatter`; default=18', 'Validator' : lambda value: isinstance(value,(int,float)) }, - 'mav' : { 'Default' : None, - 'Description' : '', - 'Validator' : _mav_validator }, + 'color' : { 'Default' : None, + 'Description' : 'color of line, scatter marker, or bar', + 'Validator' : lambda value: mcolors.is_color_like(value) or + (isinstance(value,(list,tuple,np.ndarray)) and all([mcolors.is_color_like(v) for v in value])) }, - 'panel' : { 'Default' : 0, - 'Description' : '', - 'Validator' : lambda value: _valid_panel_id(value) }, + 'linestyle' : { 'Default' : None, + 'Description' : 'line style for `type=line` ('+str(valid_linestyles)+')', + 'Validator' : lambda value: value in valid_linestyles }, - 'scatter' : { 'Default' : False, + 'width' : { 'Default' : None, # width of `bar` or `line` 'Description' : '', - 'Validator' : lambda value: isinstance(value,bool) }, + 'Validator' : lambda value: isinstance(value,(int,float)) or + all([isinstance(v,(int,float)) for v in value]) }, + + 'bottom' : { 'Default' : 0, # bottom for `type=bar` plots + 'Description' : 'bottom value for `type=bar` bars. Default=0', + 'Validator' : lambda value: isinstance(value,(int,float)) or + all([isinstance(v,(int,float)) for v in value]) }, + 'alpha' : { 'Default' : 1, # alpha of `bar`, `line`, or `scatter` + 'Description' : 'opacity for 0.0 (transparent) to 1.0 (opaque)', + 'Validator' : lambda value: isinstance(value,(int,float)) or + all([isinstance(v,(int,float)) for v in value]) }, 'secondary_y' : { 'Default' : 'auto', 'Description' : '', - 'Validator' : lambda value: isinstance(value,bool) - or value == 'auto' }, - 'stepwhere' : { 'Default' : 'pre', - 'Description' : '', - 'Validator' : lambda value : value in valid_stepwheres }, + 'Validator' : lambda value: isinstance(value,bool) or value == 'auto' }, - 'title' : { 'Default' : None, + 'y_on_right' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,bool) }, + + 'ylabel' : { 'Default' : None, 'Description' : '', 'Validator' : lambda value: isinstance(value,str) }, - 'type' : { 'Default' : 'line', + 'ylim' : {'Default' : None, 'Description' : '', - 'Validator' : lambda value: value in valid_types }, + 'Validator' : lambda value: isinstance(value, (list,tuple)) and len(value) == 2 + and all([isinstance(v,(int,float)) for v in value])}, - 'width' : { 'Default' : None, # width of `bar` or `line` + 'title' : { 'Default' : None, 'Description' : '', - 'Validator' : lambda value: isinstance(value,(int,float)) - or all([isinstance(v,(int,float)) for v in value]) }, - - 'ylabel' : { 'Default' : None, - 'Description' : 'Label for y axis.', 'Validator' : lambda value: isinstance(value,str) }, - 'ylim' : { 'Default' : None, - 'Description' : 'Limit values (upper and lower) for the y axis.', - 'Validator' : lambda value: isinstance(value, (list,tuple)) - and len(value) == 2 - and all([isinstance(v,(int,float)) for v in value]) }, + 'ax' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,mpl_axes.Axes) }, 'yscale' : { 'Default' : None, 'Description' : '', 'Validator' : lambda value: _yscale_validator(value) }, - 'y_on_right' : { 'Default' : None, + 'stepwhere' : { 'Default' : 'pre', 'Description' : '', - 'Validator' : lambda value: isinstance(value,bool) }, + 'Validator' : lambda value : value in valid_stepwheres }, } _validate_vkwargs_dict(vkwargs) From 5444dae9725681757769b721b7b89f529d53945d Mon Sep 17 00:00:00 2001 From: Daniel Goldfarb Date: Wed, 5 Jan 2022 14:38:56 -0500 Subject: [PATCH 05/14] df_wrapcols() and make_left_formatter() helpers. --- .gitignore | 18 ++++++ examples/scratch_pad/fmtr.py | 108 +++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 examples/scratch_pad/fmtr.py diff --git a/.gitignore b/.gitignore index d84d5b9d..61b5c479 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,21 @@ __pycache__ .tox/ .cache/ *.code-workspace +examples/.ipynb_checkpoints/ +examples/scratch_pad/.ipynb_checkpoints/ +examples/issue461.py +examples/macd.py +examples/mpf_demo2.py +examples/price-movement_plots.retcalcvals.ipynb +examples/scratch_pad/comp.csv +examples/scratch_pad/issue466.py +examples/scratch_pad/issues/.ipynb_checkpoints/ +examples/scratch_pad/issues/issue430.orig.py +examples/scratch_pad/issues/issue430.py +examples/scratch_pad/issues/issue455/ +examples/scratch_pad/issues/issue487_pie_chart.ipynb +examples/scratch_pad/so70145937.ipynb +examples/scratch_pad/so70240809.ipynb +examples/scratch_pad/so70418851.py +examples/scratch_pad/so70418851_data.csv +examples/scratch_pad/so70498007.ipynb diff --git a/examples/scratch_pad/fmtr.py b/examples/scratch_pad/fmtr.py new file mode 100644 index 00000000..3e64665a --- /dev/null +++ b/examples/scratch_pad/fmtr.py @@ -0,0 +1,108 @@ +#################################################################### +# +# https://stackoverflow.com/questions/25777037/how-can-i-left-justify-text-in-a-pandas-dataframe-column-in-an-ipython-notebook +# +#################################################################### + +import mplfinance as mpf +import pandas as pd +import textwrap + +vk = mpf.plotting._valid_plot_kwargs() + +df = (pd.DataFrame(vk).T.head(18)).drop('Validator',axis=1) + +df['Kwarg'] = df.index.values +df['Default'] = ["'"+d+"'" if isinstance(d,str) else str(d) for d in df['Default']] + +df = df[['Kwarg','Default','Description']] +df = df.head(5).append(df.tail(7)) + +# df.sort_index(inplace=True) + +df + +print('===========================') + +print(df) + +print('===========================') + +def make_left_formatter(maxwidth): + wm3 = maxwidth-3 + w = maxwidth + def left_formatter(value): + if not isinstance(value,str): + return f'{value:<}' + elif value[0:maxwidth] == '-'*maxwidth: + return f'{value:<{w}.{w}s}' + #elif len(value) > maxwidth and value[0:maxwidth] != '-'*maxwidth: + elif len(value) > maxwidth: + return f'{value:<{wm3}.{wm3}s}...' + else: + return f'{value:<{w}.{w}s}' + return left_formatter + +WRAPLEN=55 + +def df_wrapcol(df,wrap_column=None,wrap_length=None): + + if wrap_column is None: return df + if wrap_length is None: return df + + index = [] + columns = {} + for col in df.columns: + columns[col] = [] + nonwrapcols = [col for col in df.columns if col != wrap_column] + + for ix in df.index: + row = df.loc[ix,] + + swrap = str(row[wrap_column]) + tw = textwrap.wrap(swrap,wrap_length) if not swrap.isspace() else [' '] + + columns[wrap_column].append(tw[0]) + index.append(str(ix)) + for col in nonwrapcols: + columns[col].append(row[col]) + + if len(tw) > 1: + for r in range(1,len(tw)): + columns[wrap_column].append(tw[r]) + index.append(str(ix)+'.'+str(r)) + for col in nonwrapcols: + columns[col].append(' ') + + return pd.DataFrame(columns,index=index) + + +df = df_wrapcol(df,wrap_column='Description',wrap_length=WRAPLEN) +print('===========================') +print('dfnew1=',df) + + +# print('===========================') +# df.columns = [ ' '+col for col in df.columns ] + +dividers = [] +for col in df.columns: + dividers.append('-'*int(df[col].str.len().max())) +dfd = pd.DataFrame(dividers).T +dfd.columns = df.columns +dfd.index = pd.Index(['---']) + +print('===========================') + +df = dfd.append(df) + +fmts = {'Kwarg': make_left_formatter(df['Kwarg'].str.len().max()+1), + 'Description': make_left_formatter(WRAPLEN), + 'Default': make_left_formatter(8), + } +s = df.to_string(formatters=fmts,index=False,justify='left') + +print('\n ',s.replace('\n','\n ')) + +print('===========================') + From 35b17791ce76925aef52c467eec4797e0374dcac Mon Sep 17 00:00:00 2001 From: Daniel Goldfarb Date: Thu, 6 Jan 2022 22:06:59 -0500 Subject: [PATCH 06/14] more general df_wrapcols() method that can wrap multiple columns --- examples/scratch_pad/fmtr.py | 64 ++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/examples/scratch_pad/fmtr.py b/examples/scratch_pad/fmtr.py index 3e64665a..a6bfd763 100644 --- a/examples/scratch_pad/fmtr.py +++ b/examples/scratch_pad/fmtr.py @@ -43,41 +43,49 @@ def left_formatter(value): return f'{value:<{w}.{w}s}' return left_formatter -WRAPLEN=55 +def df_wrapcols(df,wrap_columns=None): -def df_wrapcol(df,wrap_column=None,wrap_length=None): + if wrap_columns is None: return df + if not isinstance(wrap_columns,dict): + raise TypeError('wrap_columns must be a dict of column_names and wrap_lengths') - if wrap_column is None: return df - if wrap_length is None: return df + for col in wrap_columns: + if col not in df.columns: + raise ValueError('column "'+str(col)+'" not found in df.columns') index = [] - columns = {} + column_data = {} for col in df.columns: - columns[col] = [] - nonwrapcols = [col for col in df.columns if col != wrap_column] - + column_data[col] = [] + for ix in df.index: row = df.loc[ix,] - - swrap = str(row[wrap_column]) - tw = textwrap.wrap(swrap,wrap_length) if not swrap.isspace() else [' '] - - columns[wrap_column].append(tw[0]) - index.append(str(ix)) - for col in nonwrapcols: - columns[col].append(row[col]) - - if len(tw) > 1: - for r in range(1,len(tw)): - columns[wrap_column].append(tw[r]) - index.append(str(ix)+'.'+str(r)) - for col in nonwrapcols: - columns[col].append(' ') - - return pd.DataFrame(columns,index=index) - - -df = df_wrapcol(df,wrap_column='Description',wrap_length=WRAPLEN) + + row_data = {} + for col in row.index: + cstr = str(row[col]) + if col in wrap_columns: + wlen = wrap_columns[col] + tw = textwrap.wrap(cstr,wlen) if not cstr.isspace() else [' '] + else: + tw = [cstr] + row_data[col] = tw + + cmax = max(row_data,key=lambda k: len(row_data[k])) + rlen = len(row_data[cmax]) + for r in range(rlen): + for col in row.index: + extension = [' ']*(rlen - len(row_data[col])) + row_data[col].extend(extension) + column_data[col].append(row_data[col][r]) + ixstr = str(ix)+'.'+str(r) if r > 0 else str(ix) + index.append(ixstr) + + return pd.DataFrame(column_data,index=index) + +WRAPLEN = 55 + +df = df_wrapcols(df,wrap_columns={'Description':WRAPLEN}) print('===========================') print('dfnew1=',df) From 7d5514a495ac7d51a3187c74a21a5c7f67c36977 Mon Sep 17 00:00:00 2001 From: Daniel Goldfarb Date: Fri, 7 Jan 2022 14:33:47 -0500 Subject: [PATCH 07/14] first cut kwarg_help() method --- src/mplfinance/__init__.py | 11 +- src/mplfinance/_kwarg_help.py | 204 ++++++++++++++++++++++++++++++++++ 2 files changed, 210 insertions(+), 5 deletions(-) create mode 100644 src/mplfinance/_kwarg_help.py diff --git a/src/mplfinance/__init__.py b/src/mplfinance/__init__.py index 17d5b739..f1e1865c 100644 --- a/src/mplfinance/__init__.py +++ b/src/mplfinance/__init__.py @@ -1,6 +1,7 @@ import mplfinance._mpf_warnings -from mplfinance.plotting import plot, make_addplot -from mplfinance._styles import make_mpf_style, make_marketcolors -from mplfinance._styles import available_styles, write_style_file -from mplfinance._version import __version__ -from mplfinance._mplwraps import figure, show +from mplfinance.plotting import plot, make_addplot +from mplfinance._styles import make_mpf_style, make_marketcolors +from mplfinance._styles import available_styles, write_style_file +from mplfinance._version import __version__ +from mplfinance._mplwraps import figure, show +from mplfinance._kwarg_help import kwarg_help diff --git a/src/mplfinance/_kwarg_help.py b/src/mplfinance/_kwarg_help.py new file mode 100644 index 00000000..21941ada --- /dev/null +++ b/src/mplfinance/_kwarg_help.py @@ -0,0 +1,204 @@ +import mplfinance as mpf +import pandas as pd +import textwrap + +def df_wrapcols(df,wrap_columns=None): + + if wrap_columns is None: return df + if not isinstance(wrap_columns,dict): + raise TypeError('wrap_columns must be a dict of column_names and wrap_lengths') + + for col in wrap_columns: + if col not in df.columns: + raise ValueError('column "'+str(col)+'" not found in df.columns') + + index = [] + column_data = {} + for col in df.columns: + column_data[col] = [] + + for ix in df.index: + row = df.loc[ix,] + + row_data = {} + for col in row.index: + cstr = str(row[col]) + if col in wrap_columns: + wlen = wrap_columns[col] + tw = textwrap.wrap(cstr,wlen) if not cstr.isspace() else [' '] + else: + tw = [cstr] + row_data[col] = tw + + cmax = max(row_data,key=lambda k: len(row_data[k])) + rlen = len(row_data[cmax]) + for r in range(rlen): + for col in row.index: + extension = [' ']*(rlen - len(row_data[col])) + row_data[col].extend(extension) + column_data[col].append(row_data[col][r]) + ixstr = str(ix)+'.'+str(r) if r > 0 else str(ix) + index.append(ixstr) + + return pd.DataFrame(column_data,index=index) + +def make_left_formatter(maxwidth): + wm3 = maxwidth-3 + w = maxwidth + def left_formatter(value): + if not isinstance(value,str): + return f'{value:<}' + elif value[0:maxwidth] == '-'*maxwidth: + return f'{value:<{w}.{w}s}' + #elif len(value) > maxwidth and value[0:maxwidth] != '-'*maxwidth: + elif len(value) > maxwidth: + return f'{value:<{wm3}.{wm3}s}...' + else: + return f'{value:<{w}.{w}s}' + return left_formatter + + +def kwarg_help( func_name, kwarg_names=None ): + + func_kwarg_map = { + 'plot' : mpf.plotting._valid_plot_kwargs, + 'make_addplot' : mpf.plotting._valid_addplot_kwargs, + 'addplot' : mpf.plotting._valid_addplot_kwargs, + 'make_marketcolors' : mpf._styles._valid_make_marketcolors_kwargs, + 'marketcolors' : mpf._styles._valid_make_marketcolors_kwargs, + 'make_mpf_style' : mpf._styles._valid_make_mpf_style_kwargs, + 'mpf_style' : mpf._styles._valid_make_mpf_style_kwargs, + 'style' : mpf._styles._valid_make_mpf_style_kwargs, + 'renko_params' : mpf._utils._valid_renko_kwargs, + 'renko' : mpf._utils._valid_renko_kwargs, + 'pnf_params' : mpf._utils._valid_pnf_kwargs, + 'pnf' : mpf._utils._valid_pnf_kwargs, + 'hlines' : mpf._utils._valid_lines_kwargs, + 'alines' : mpf._utils._valid_lines_kwargs, + 'tlines' : mpf._utils._valid_lines_kwargs, + 'vlines' : mpf._utils._valid_lines_kwargs, + 'lines' : mpf._utils._valid_lines_kwargs, + } + + if func_name not in func_kwarg_map: + raise ValueError('Function name "'+func_name+'" NOT a valid function name') + + print('func_name=',func_name) + + vks = func_kwarg_map[func_name]() + + df = (pd.DataFrame(vks).T.head(18)).drop('Validator',axis=1) + print('valid kwargs=\n',df) + + +kwarg_help('plot') +kwarg_help('xyz') + + + +# vk = mpf.plotting._valid_plot_kwargs() +# +# df = (pd.DataFrame(vk).T.head(18)).drop('Validator',axis=1) +# +# df['Kwarg'] = df.index.values +# df['Default'] = ["'"+d+"'" if isinstance(d,str) else str(d) for d in df['Default']] +# +# df = df[['Kwarg','Default','Description']] +# df = df.head(5).append(df.tail(7)) +# +# # df.sort_index(inplace=True) +# +# df +# +# print('===========================') +# +# print(df) +# +# print('===========================') +# +# def make_left_formatter(maxwidth): +# wm3 = maxwidth-3 +# w = maxwidth +# def left_formatter(value): +# if not isinstance(value,str): +# return f'{value:<}' +# elif value[0:maxwidth] == '-'*maxwidth: +# return f'{value:<{w}.{w}s}' +# #elif len(value) > maxwidth and value[0:maxwidth] != '-'*maxwidth: +# elif len(value) > maxwidth: +# return f'{value:<{wm3}.{wm3}s}...' +# else: +# return f'{value:<{w}.{w}s}' +# return left_formatter +# +# def df_wrapcols(df,wrap_columns=None): +# +# if wrap_columns is None: return df +# if not isinstance(wrap_columns,dict): +# raise TypeError('wrap_columns must be a dict of column_names and wrap_lengths') +# +# for col in wrap_columns: +# if col not in df.columns: +# raise ValueError('column "'+str(col)+'" not found in df.columns') +# +# index = [] +# column_data = {} +# for col in df.columns: +# column_data[col] = [] +# +# for ix in df.index: +# row = df.loc[ix,] +# +# row_data = {} +# for col in row.index: +# cstr = str(row[col]) +# if col in wrap_columns: +# wlen = wrap_columns[col] +# tw = textwrap.wrap(cstr,wlen) if not cstr.isspace() else [' '] +# else: +# tw = [cstr] +# row_data[col] = tw +# +# cmax = max(row_data,key=lambda k: len(row_data[k])) +# rlen = len(row_data[cmax]) +# for r in range(rlen): +# for col in row.index: +# extension = [' ']*(rlen - len(row_data[col])) +# row_data[col].extend(extension) +# column_data[col].append(row_data[col][r]) +# ixstr = str(ix)+'.'+str(r) if r > 0 else str(ix) +# index.append(ixstr) +# +# return pd.DataFrame(column_data,index=index) +# +# WRAPLEN = 55 +# +# df = df_wrapcols(df,wrap_columns={'Description':WRAPLEN}) +# print('===========================') +# print('dfnew1=',df) +# +# +# # print('===========================') +# # df.columns = [ ' '+col for col in df.columns ] +# +# dividers = [] +# for col in df.columns: +# dividers.append('-'*int(df[col].str.len().max())) +# dfd = pd.DataFrame(dividers).T +# dfd.columns = df.columns +# dfd.index = pd.Index(['---']) +# +# print('===========================') +# +# df = dfd.append(df) +# +# fmts = {'Kwarg': make_left_formatter(df['Kwarg'].str.len().max()+1), +# 'Description': make_left_formatter(WRAPLEN), +# 'Default': make_left_formatter(8), +# } +# s = df.to_string(formatters=fmts,index=False,justify='left') +# +# print('\n ',s.replace('\n','\n ')) +# +# print('===========================') +# From 52c3b546397942084684a13c0787c78ec9dba8af Mon Sep 17 00:00:00 2001 From: Daniel Goldfarb Date: Tue, 11 Jan 2022 13:59:53 -0500 Subject: [PATCH 08/14] _kwarg_help() working version --- src/mplfinance/_kwarg_help.py | 196 ++++++++++++---------------------- 1 file changed, 69 insertions(+), 127 deletions(-) diff --git a/src/mplfinance/_kwarg_help.py b/src/mplfinance/_kwarg_help.py index 21941ada..ae2db172 100644 --- a/src/mplfinance/_kwarg_help.py +++ b/src/mplfinance/_kwarg_help.py @@ -50,7 +50,6 @@ def left_formatter(value): return f'{value:<}' elif value[0:maxwidth] == '-'*maxwidth: return f'{value:<{w}.{w}s}' - #elif len(value) > maxwidth and value[0:maxwidth] != '-'*maxwidth: elif len(value) > maxwidth: return f'{value:<{wm3}.{wm3}s}...' else: @@ -58,147 +57,90 @@ def left_formatter(value): return left_formatter -def kwarg_help( func_name, kwarg_names=None ): +def kwarg_help( func_name=None, kwarg_names=None ): func_kwarg_map = { 'plot' : mpf.plotting._valid_plot_kwargs, 'make_addplot' : mpf.plotting._valid_addplot_kwargs, - 'addplot' : mpf.plotting._valid_addplot_kwargs, 'make_marketcolors' : mpf._styles._valid_make_marketcolors_kwargs, - 'marketcolors' : mpf._styles._valid_make_marketcolors_kwargs, 'make_mpf_style' : mpf._styles._valid_make_mpf_style_kwargs, + 'renko_params' : mpf._utils._valid_renko_kwargs, + 'pnf_params' : mpf._utils._valid_pnf_kwargs, + 'lines' : mpf._utils._valid_lines_kwargs, + } + + func_kwarg_aliases = { + 'addplot' : mpf.plotting._valid_addplot_kwargs, + 'marketcolors' : mpf._styles._valid_make_marketcolors_kwargs, 'mpf_style' : mpf._styles._valid_make_mpf_style_kwargs, 'style' : mpf._styles._valid_make_mpf_style_kwargs, - 'renko_params' : mpf._utils._valid_renko_kwargs, 'renko' : mpf._utils._valid_renko_kwargs, - 'pnf_params' : mpf._utils._valid_pnf_kwargs, 'pnf' : mpf._utils._valid_pnf_kwargs, 'hlines' : mpf._utils._valid_lines_kwargs, 'alines' : mpf._utils._valid_lines_kwargs, 'tlines' : mpf._utils._valid_lines_kwargs, 'vlines' : mpf._utils._valid_lines_kwargs, - 'lines' : mpf._utils._valid_lines_kwargs, } - if func_name not in func_kwarg_map: + if func_name is None: + print('\nUsage: `kwarg_help(func_name)` or `kwarg_help(func_name,kwarg_names)`') + print(' kwarg_help is available for the following func_names:') + s = str(list(func_kwarg_map.keys())) + text = textwrap.wrap(s,68) + for t in text: + print(' ',t) + print() + return + + fkmap = {**func_kwarg_map, **func_kwarg_aliases} + + if func_name not in fkmap: raise ValueError('Function name "'+func_name+'" NOT a valid function name') - print('func_name=',func_name) - - vks = func_kwarg_map[func_name]() - - df = (pd.DataFrame(vks).T.head(18)).drop('Validator',axis=1) - print('valid kwargs=\n',df) - - -kwarg_help('plot') -kwarg_help('xyz') - - - -# vk = mpf.plotting._valid_plot_kwargs() -# -# df = (pd.DataFrame(vk).T.head(18)).drop('Validator',axis=1) -# -# df['Kwarg'] = df.index.values -# df['Default'] = ["'"+d+"'" if isinstance(d,str) else str(d) for d in df['Default']] -# -# df = df[['Kwarg','Default','Description']] -# df = df.head(5).append(df.tail(7)) -# -# # df.sort_index(inplace=True) -# -# df -# -# print('===========================') -# -# print(df) -# -# print('===========================') -# -# def make_left_formatter(maxwidth): -# wm3 = maxwidth-3 -# w = maxwidth -# def left_formatter(value): -# if not isinstance(value,str): -# return f'{value:<}' -# elif value[0:maxwidth] == '-'*maxwidth: -# return f'{value:<{w}.{w}s}' -# #elif len(value) > maxwidth and value[0:maxwidth] != '-'*maxwidth: -# elif len(value) > maxwidth: -# return f'{value:<{wm3}.{wm3}s}...' -# else: -# return f'{value:<{w}.{w}s}' -# return left_formatter -# -# def df_wrapcols(df,wrap_columns=None): -# -# if wrap_columns is None: return df -# if not isinstance(wrap_columns,dict): -# raise TypeError('wrap_columns must be a dict of column_names and wrap_lengths') -# -# for col in wrap_columns: -# if col not in df.columns: -# raise ValueError('column "'+str(col)+'" not found in df.columns') -# -# index = [] -# column_data = {} -# for col in df.columns: -# column_data[col] = [] -# -# for ix in df.index: -# row = df.loc[ix,] -# -# row_data = {} -# for col in row.index: -# cstr = str(row[col]) -# if col in wrap_columns: -# wlen = wrap_columns[col] -# tw = textwrap.wrap(cstr,wlen) if not cstr.isspace() else [' '] -# else: -# tw = [cstr] -# row_data[col] = tw -# -# cmax = max(row_data,key=lambda k: len(row_data[k])) -# rlen = len(row_data[cmax]) -# for r in range(rlen): -# for col in row.index: -# extension = [' ']*(rlen - len(row_data[col])) -# row_data[col].extend(extension) -# column_data[col].append(row_data[col][r]) -# ixstr = str(ix)+'.'+str(r) if r > 0 else str(ix) -# index.append(ixstr) -# -# return pd.DataFrame(column_data,index=index) -# -# WRAPLEN = 55 -# -# df = df_wrapcols(df,wrap_columns={'Description':WRAPLEN}) -# print('===========================') -# print('dfnew1=',df) -# -# -# # print('===========================') -# # df.columns = [ ' '+col for col in df.columns ] -# -# dividers = [] -# for col in df.columns: -# dividers.append('-'*int(df[col].str.len().max())) -# dfd = pd.DataFrame(dividers).T -# dfd.columns = df.columns -# dfd.index = pd.Index(['---']) -# -# print('===========================') -# -# df = dfd.append(df) -# -# fmts = {'Kwarg': make_left_formatter(df['Kwarg'].str.len().max()+1), -# 'Description': make_left_formatter(WRAPLEN), -# 'Default': make_left_formatter(8), -# } -# s = df.to_string(formatters=fmts,index=False,justify='left') -# -# print('\n ',s.replace('\n','\n ')) -# -# print('===========================') -# + if kwarg_names is not None and isinstance(kwarg_names,str): + kwarg_names = [ kwarg_names, ] + + if ( kwarg_names is not None + and (not isinstance(kwarg_names,(list,tuple)) + or not all([isinstance(k,str) for k in kwarg_names]) + ) + ): + raise ValueError('kwarg_names must be a sequence (list,tuple) of strings') + + vks = fkmap[func_name]() + + df = (pd.DataFrame(vks).T).drop('Validator',axis=1) + df.index.name = 'Kwarg' + df.reset_index(inplace=True) + + if kwarg_names is not None: + for k in kwarg_names: + if k not in df['Kwarg'].values: + print(' Warning: "'+k+'" is not a valid `kwarg_name` for `func_name` "'+func_name,'"') + df = df[ df['Kwarg'].isin(kwarg_names) ] + if len(df) < 1: + raise ValueError(' None of specified `kwarg_names` are valid for `func_name` "'+func_name,'"') + + wraplen = 80 - (df['Kwarg'].str.len().max()+1 + 8) + df = df_wrapcols(df,wrap_columns={'Description':wraplen}) + + dividers = [] + for col in df.columns: + dividers.append('-'*int(df[col].str.len().max())) + dfd = pd.DataFrame(dividers).T + dfd.columns = df.columns + dfd.index = pd.Index(['---']) + + df = dfd.append(df) + + formatters = { 'Kwarg' : make_left_formatter(df['Kwarg'].str.len().max()+1), + 'Default' : make_left_formatter( 8 ), + 'Description' : make_left_formatter( wraplen ), + } + + print('\n ','-'*78) + print(' Kwargs for func_name "'+func_name+'":') + + s = df.to_string(formatters=formatters,index=False,justify='left') + + print('\n ',s.replace('\n','\n ')) From 24a67cd1bf362a38e2062f633698555d785a81b6 Mon Sep 17 00:00:00 2001 From: Daniel Goldfarb Date: Tue, 11 Jan 2022 14:11:30 -0500 Subject: [PATCH 09/14] remove temporary .gitignore entries --- .gitignore | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/.gitignore b/.gitignore index 61b5c479..f9b2210e 100644 --- a/.gitignore +++ b/.gitignore @@ -9,19 +9,3 @@ __pycache__ *.code-workspace examples/.ipynb_checkpoints/ examples/scratch_pad/.ipynb_checkpoints/ -examples/issue461.py -examples/macd.py -examples/mpf_demo2.py -examples/price-movement_plots.retcalcvals.ipynb -examples/scratch_pad/comp.csv -examples/scratch_pad/issue466.py -examples/scratch_pad/issues/.ipynb_checkpoints/ -examples/scratch_pad/issues/issue430.orig.py -examples/scratch_pad/issues/issue430.py -examples/scratch_pad/issues/issue455/ -examples/scratch_pad/issues/issue487_pie_chart.ipynb -examples/scratch_pad/so70145937.ipynb -examples/scratch_pad/so70240809.ipynb -examples/scratch_pad/so70418851.py -examples/scratch_pad/so70418851_data.csv -examples/scratch_pad/so70498007.ipynb From 78e2efca91b34648e5d5ee128351c2866fdb1707 Mon Sep 17 00:00:00 2001 From: Daniel Goldfarb Date: Tue, 11 Jan 2022 15:08:03 -0500 Subject: [PATCH 10/14] bring in sync with matplotlib/mplfinance master --- src/mplfinance/_styles.py | 12 ++++++------ src/mplfinance/_utils.py | 25 ------------------------- 2 files changed, 6 insertions(+), 31 deletions(-) diff --git a/src/mplfinance/_styles.py b/src/mplfinance/_styles.py index 7280bef7..62ce2eca 100644 --- a/src/mplfinance/_styles.py +++ b/src/mplfinance/_styles.py @@ -209,15 +209,15 @@ def _valid_make_marketcolors_kwargs(): vkwargs = { 'up' : { 'Default' : None, 'Description' : '', - 'Validator' : lambda value: mcolors.is_color_like(value) }, + 'Validator' : lambda value: _mpf_is_color_like(value) }, 'down' : { 'Default' : None, 'Description' : '', - 'Validator' : lambda value: mcolors.is_color_like(value) }, + 'Validator' : lambda value: _mpf_is_color_like(value) }, 'hollow' : { 'Default' : None, 'Description' : '', - 'Validator' : lambda value: mcolors.is_color_like(value) }, + 'Validator' : lambda value: _mpf_is_color_like(value) }, 'alpha' : { 'Default' : None, 'Description' : '', @@ -232,19 +232,19 @@ def _valid_make_marketcolors_kwargs(): 'Description' : '', 'Validator' : lambda value: isinstance(value,dict) or isinstance(value,str) - or mcolors.is_color_like(value) }, + or _mpf_is_color_like(value) }, 'ohlc' : { 'Default' : None, 'Description' : '', 'Validator' : lambda value: isinstance(value,dict) or isinstance(value,str) - or mcolors.is_color_like(value) }, + or _mpf_is_color_like(value) }, 'volume' : { 'Default' : None, 'Description' : '', 'Validator' : lambda value: isinstance(value,dict) or isinstance(value,str) - or mcolors.is_color_like(value) }, + or _mpf_is_color_like(value) }, 'vcdopcod' : { 'Default' : False, 'Description' : '', diff --git a/src/mplfinance/_utils.py b/src/mplfinance/_utils.py index 9db716c4..4c169b10 100644 --- a/src/mplfinance/_utils.py +++ b/src/mplfinance/_utils.py @@ -1444,31 +1444,6 @@ def _tline_lsq(dfslice,tline_use): return _construct_aline_collections(alines, dtix) -def _display_formetted_kwargs_table(kwargs_dict: dict): - """ - Displays through stdout the provided kwargs dict along with each - one of the discriptions and default values. - - Parameters - -------------- - kwargs_dict : dict - Dictionary containing the kwargs in the format (kwarg, default, description) - """ - - # TODO must be defined the best way to place it in the API - # (either inside the 'plot' method or some other auxiliary - # method) - - # prints header of the table - print('=' * 120) - print("{:<30} {:<15} {}".format('kwarg', 'Default', 'Description')) - print('=' * 120) - - for kwarg, info in kwargs_dict.items(): - print(f'{kwarg:30} {str(info["Default"]):15} {info["Description"]}') - print('-' * 120) - - from matplotlib.ticker import Formatter class IntegerIndexDateTimeFormatter(Formatter): """ From ef6bc4159a599963180131411ec0b1c83976322a Mon Sep 17 00:00:00 2001 From: Daniel Goldfarb Date: Tue, 11 Jan 2022 15:08:59 -0500 Subject: [PATCH 11/14] bump version --- src/mplfinance/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mplfinance/_version.py b/src/mplfinance/_version.py index 4b58f268..9af54986 100644 --- a/src/mplfinance/_version.py +++ b/src/mplfinance/_version.py @@ -1,5 +1,5 @@ -version_info = (0, 12, 8, 'beta', 6) +version_info = (0, 12, 8, 'beta', 7) _specifier_ = {'alpha': 'a','beta': 'b','candidate': 'rc','final': ''} From 26d3def2e9fc7958e08eec7b904f04a1e36af0bf Mon Sep 17 00:00:00 2001 From: Daniel Goldfarb Date: Tue, 11 Jan 2022 15:30:10 -0500 Subject: [PATCH 12/14] add `scale_width_adjustment` and `update_width_config` to kwarg help --- src/mplfinance/_kwarg_help.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mplfinance/_kwarg_help.py b/src/mplfinance/_kwarg_help.py index ae2db172..3f7ee0b6 100644 --- a/src/mplfinance/_kwarg_help.py +++ b/src/mplfinance/_kwarg_help.py @@ -67,6 +67,8 @@ def kwarg_help( func_name=None, kwarg_names=None ): 'renko_params' : mpf._utils._valid_renko_kwargs, 'pnf_params' : mpf._utils._valid_pnf_kwargs, 'lines' : mpf._utils._valid_lines_kwargs, + 'scale_width_adjustment': mpf._widths._valid_scale_width_kwargs, + 'update_width_config': mpf._widths._valid_update_width_kwargs, } func_kwarg_aliases = { From 9c32bf6f95a13a35c021db250a08773d066d4bbe Mon Sep 17 00:00:00 2001 From: Daniel Goldfarb Date: Tue, 11 Jan 2022 15:38:33 -0500 Subject: [PATCH 13/14] quote string defaults; handle len of default values --- src/mplfinance/_kwarg_help.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/mplfinance/_kwarg_help.py b/src/mplfinance/_kwarg_help.py index 3f7ee0b6..75643908 100644 --- a/src/mplfinance/_kwarg_help.py +++ b/src/mplfinance/_kwarg_help.py @@ -122,8 +122,13 @@ def kwarg_help( func_name=None, kwarg_names=None ): df = df[ df['Kwarg'].isin(kwarg_names) ] if len(df) < 1: raise ValueError(' None of specified `kwarg_names` are valid for `func_name` "'+func_name,'"') + + df['Default'] = ["'"+d+"'" if isinstance(d,str) else str(d) for d in df['Default']] - wraplen = 80 - (df['Kwarg'].str.len().max()+1 + 8) + klen = df['Kwarg'].str.len().max()+1 + dlen = df['Default'].str.len().max()+1 + + wraplen = 80 - ( klen + dlen ) df = df_wrapcols(df,wrap_columns={'Description':wraplen}) dividers = [] @@ -135,8 +140,8 @@ def kwarg_help( func_name=None, kwarg_names=None ): df = dfd.append(df) - formatters = { 'Kwarg' : make_left_formatter(df['Kwarg'].str.len().max()+1), - 'Default' : make_left_formatter( 8 ), + formatters = { 'Kwarg' : make_left_formatter( klen ), + 'Default' : make_left_formatter( dlen ), 'Description' : make_left_formatter( wraplen ), } From 241600408ae5598291c013bb7828874bb64eac56 Mon Sep 17 00:00:00 2001 From: Daniel Goldfarb Date: Tue, 11 Jan 2022 15:45:27 -0500 Subject: [PATCH 14/14] fix potential bug; wraplen must be > 0 (default to >=40) --- src/mplfinance/_kwarg_help.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mplfinance/_kwarg_help.py b/src/mplfinance/_kwarg_help.py index 75643908..ee5e70ca 100644 --- a/src/mplfinance/_kwarg_help.py +++ b/src/mplfinance/_kwarg_help.py @@ -128,7 +128,7 @@ def kwarg_help( func_name=None, kwarg_names=None ): klen = df['Kwarg'].str.len().max()+1 dlen = df['Default'].str.len().max()+1 - wraplen = 80 - ( klen + dlen ) + wraplen = max( 40, 80-(klen+dlen) ) df = df_wrapcols(df,wrap_columns={'Description':wraplen}) dividers = []