def _valid_addplot_kwargs(): valid_linestyles = ('-','solid','--','dashed','-.','dashdot','.','dotted',None,' ','') valid_types = ('line','scatter','bar', 'ohlc', 'candle') vkwargs = { 'scatter' : { 'Default' : False, 'Validator' : lambda value: isinstance(value,bool) }, 'type' : { 'Default' : 'line', 'Validator' : lambda value: value in valid_types }, 'mav' : { 'Default' : None, 'Validator' : _mav_validator }, 'panel' : { 'Default' : 0, 'Validator' : lambda value: _valid_panel_id(value) }, 'marker' : { 'Default' : 'o', 'Validator' : lambda value: _bypass_kwarg_validation(value) }, 'markersize' : { 'Default' : 18, '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 }, '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]) }, '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]) }, 'secondary_y' : { 'Default' : 'auto', 'Validator' : lambda value: isinstance(value,bool) or value == 'auto' }, 'y_on_right' : { 'Default' : None, 'Validator' : lambda value: isinstance(value,bool) }, 'ylabel' : { 'Default' : None, '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])}, } _validate_vkwargs_dict(vkwargs) return vkwargs
def _valid_plot_kwargs(): ''' Construct and return the "valid kwargs table" for the mplfinance.plot() 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: "Default" - The default value for the kwarg if none is specified. "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 kwarg value is one of the allowed values. ''' 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) }, '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, '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 '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 'Validator' : lambda value: isinstance(value,(tuple,list)) and len(value) == 2 and isinstance(value[0],(float,int)) and isinstance(value[1],(float,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) }, '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) }, '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: isinstance(value, (list,tuple)) and len(value) == 2 and all([isinstance(v,(int,float)) for v in value])}, 'set_ylim_panelB' : {'Default' : None, 'Validator' : lambda value: _warn_set_ylim_deprecated(value) }, 'hlines' : { 'Default' : None, '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]) }, 'main_panel' : { 'Default' : 0, 'Validator' : lambda value: _valid_panel_id(value) }, 'volume_panel' : { 'Default' : 1, 'Validator' : lambda value: _valid_panel_id(value) }, 'num_panels' : { 'Default' : None, 'Validator' : lambda value: isinstance(value,int) and value in range(1,10+1) }, 'datetime_format' : { 'Default' : None, 'Validator' : lambda value: isinstance(value,str) }, 'xrotation' : { 'Default' : 45, 'Validator' : lambda value: isinstance(value,(int,float)) }, 'axisoff' : { 'Default' : False, 'Validator' : lambda value: isinstance(value,bool) }, 'closefig' : { 'Default' : 'auto', 'Validator' : lambda value: isinstance(value,bool) }, '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'])) }, 'tight_layout' : { 'Default' : False, '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_width_config' : { 'Default' : None, 'Validator' : lambda value: isinstance(value,dict) and len(value)==0 }, 'saxbelow' : { 'Default' : True, # Issue#115 Comment#639446764 'Validator' : lambda value: isinstance(value,bool) }, 'scale_padding' : { 'Default' : 1.0, # Issue#193 'Validator' : lambda value: _scale_padding_validator(value) }, 'ax' : { 'Default' : None, 'Validator' : lambda value: isinstance(value,mpl_axes.Axes) }, 'volume_exponent' : { 'Default' : None, 'Validator' : lambda value: isinstance(value,int) or value == 'legacy'}, 'tz_localize' : { 'Default' : True, 'Validator' : lambda value: isinstance(value,bool) }, } _validate_vkwargs_dict(vkwargs) return vkwargs
def _build_panels( figure, config ): """ Create and return a DataFrame containing panel information and Axes objects for each panel, etc. We allow up to 10 panels, identified by their panel id (panid) which is an integer 0 through 9. Parameters ---------- figure : pyplot.Figure figure on which to create the Axes for the panels config : dict config dict from `mplfinance.plot()` Config ------ The following items are used from `config`: num_panels : integer (0-9) or None number of panels to create addplot : dict or None value for the `addplot=` kwarg passed into `mplfinance.plot()` volume_panel : integer (0-9) or None panel id (0-number_of_panels) main_panel : integer (0-9) or None panel id (0-number_of_panels) panel_ratios : sequence or None sequence of relative sizes for the panels; NOTE: If len(panel_ratios) == number of panels (regardless of whether number of panels was specified or inferred), then panel ratios are the relative sizes of each panel, in panel id order, 0 through N (where N = number of panels). If len(panel_ratios) != number of panels, then len(panel_ratios) must equal 2, and panel_ratios[0] is the relative size for the 'main' panel, and panel_ratios[1] is the relative size for all other panels. If the number of panels == 1, the panel_ratios is ignored. Returns ---------- panels : pandas.DataFrame dataframe indexed by panel id (panid) and having the following columns: axes : tuple of matplotlib.Axes (primary and secondary) for each column. used secondary : bool indicating whether or not the seconday Axes is in use. relative size : height of panel as proportion of sum of all relative sizes """ num_panels = config['num_panels'] addplot = config['addplot'] volume = config['volume'] volume_panel = config['volume_panel'] num_panels = config['num_panels'] main_panel = config['main_panel'] panel_ratios = config['panel_ratios'] if not _valid_panel_id(main_panel): raise ValueError('main_panel id must be integer 0 to 9, but is '+str(main_panel)) if num_panels is None: # then infer the number of panels: pset = {0} # start with a set including only panel zero if addplot is not None: if isinstance(addplot,dict): addplot = [addplot,] # make list of dict to be consistent elif not _list_of_dict(addplot): raise TypeError('addplot must be `dict`, or `list of dict`, NOT '+str(type(addplot))) backwards_panel_compatibility = {'main':0,'lower':1,'A':0,'B':1,'C':2} for apdict in addplot: panel = apdict['panel'] if panel in backwards_panel_compatibility: panel = backwards_panel_compatibility[panel] if not _valid_panel_id(panel): raise ValueError('addplot panel must be integer 0 to 9, but is "'+str(panel)+'"') pset.add(panel) if volume is True: if not _valid_panel_id(volume_panel): raise ValueError('volume_panel must be integer 0 to 9, but is "'+str(volume_panel)+'"') pset.add(volume_panel) pset.add(main_panel) pset = sorted(pset) missing = [m for m in range(len(pset)) if m not in pset] if len(missing) != 0: raise ValueError('inferred panel list is missing panels: '+str(missing)) else: if not isinstance(num_panels,int) or num_panels < 1 or num_panels > 10: raise ValueError('num_panels must be integer 1 to 10, but is "'+str(volume_panel)+'"') pset = range(0,num_panels) _nones = [None]*len(pset) panels = pd.DataFrame(dict(axes=_nones, relsize=_nones, lift=_nones, height=_nones, used2nd=[False]*len(pset), title=_nones, ylabel=_nones), index=pset) panels.index.name = 'panid' # Now determine the height for each panel: # ( figure, num_panels='infer', addplot=None, volume_panel=None, main_panel=0, panel_ratios=None ): if panel_ratios is not None: if not isinstance(panel_ratios,(list,tuple)): raise TypeError('panel_ratios must be a list or tuple') if len(panel_ratios) != len(panels) and not (len(panel_ratios)==2 and len(panels) > 2): err = 'len(panel_ratios) must be 2, or must be same as number of panels' err += '\nlen(panel_ratios)='+str(len(panel_ratios))+' num panels='+str(len(panels)) raise ValueError(err) if len(panel_ratios) == 2 and len(panels) > 2: pratios = [panel_ratios[1]]*len(panels) pratios[main_panel] = panel_ratios[0] else: pratios = panel_ratios else: pratios = [2]*len(panels) pratios[main_panel] = 5 panels['relsize'] = pratios #print('len(panels)=',len(panels)) #print('len(pratios)=',len(pratios)) #print('pratios=') #print(pratios) #print('panels=') #print(panels) psum = sum(pratios) for panid,size in enumerate(pratios): panels.at[panid,'height'] = 0.7 * size / psum # Now create the Axes: for panid,row in panels.iterrows(): height = row.height lift = panels['height'].loc[panid+1:].sum() panels.at[panid,'lift'] = lift if panid == 0: # rect = [left, bottom, width, height] ax0 = figure.add_axes( [0.15, 0.18+lift, 0.70, height] ) else: ax0 = figure.add_axes( [0.15, 0.18+lift, 0.70, height], sharex=panels.at[0,'axes'][0] ) ax1 = ax0.twinx() ax1.grid(False) if config['saxbelow']: # issue#115 issuecomment-639446764 ax0.set_axisbelow(True) # so grid does not show through plot data on any panel. elif panid == volume_panel: ax0.set_axisbelow(True) # so grid does not show through volume bars. panels.at[panid,'axes'] = (ax0,ax1) return panels