matplotlib / mplfinance

Financial Markets Data Visualization using Matplotlib
https://pypi.org/project/mplfinance/
Other
3.59k stars 621 forks source link

mplfinance rc params external axis and hiding figure bounding box #348

Closed pipreaper closed 3 years ago

pipreaper commented 3 years ago

I have used mplfinance to develop a front end for a instrument search algo.

I have used your code to generate bricks from renko but ended up going to external axis mode since I am interested in Icimoku cloud fill.

I simply want to remove the box surrounding the figures or at least change its color. I am confused since some parameters I pass as kwargs to plot work and some just do not. However I would have expected the following code to hide the box outline. It does not. Is something in mplfinance overrriding these settings. Other axis settings in the example code work well.

self.renko_axis.tick_params(axis='y', labelsize=chart_y_font_size, top='off', bottom='off', left='off', right='off', labelleft='on', labelbottom='on')
self.renko_axis.tick_params(axis='x', labelsize=chart_y_font_size, top='off', bottom='off', left='off', right='off', labelleft='on', labelbottom='on').

Example Code.

    def draw_renko(self):
        try:
            if self.controller.show_renko:
                if self.controller.renko_ohlc_show_boxes and self.controller.show_ohlc:
                    draw_ohlc_boxes(self, self.ohlc_axis)
                    self.canvas_ohlc.draw()
                draw_renko_boxes(self, self.renko_axis)
                self.fig_renko.suptitle(
                    'Renko: ' + remove(self.controller.ticker_symbol) + ', Period: ' + self.controller.interval + ' , Box Size:' + self.formatted_brick_size, fontsize=8)
                self.renko_axis.axes.xaxis.set_visible(False)
                self.renko_axis.set_ylabel('')
                self.renko_axis.set_facecolor(chart_face_color)
                self.renko_axis.tick_params(axis='y', labelsize=chart_y_font_size, top='off', bottom='off', left='off', right='off', labelleft='on', labelbottom='on')
                self.renko_axis.tick_params(axis='x', labelsize=chart_y_font_size, top='off', bottom='off', left='off', right='off', labelleft='on', labelbottom='on')
                self.canvas_renko.draw()
        except Exception as e:
            logger.exception(e)

I see you are doing a good job of the project but the documentation around this area is sketchy? Sure there is an easy explanation i just cant bottom it right now. Any ideas welcome

Screenshot_2021-03-02_07-32-58

DanielGoldfarb commented 3 years ago

@pipreaper It's difficult for me to tell because you have not shown any calls to any of the methods in the mplfinance library. Since you are calling mplfinance in external axes mode, for which you should be aware that some of the kwargs to mpf.plot() are ignored in external axes mode: the general rule is if the kwarg involves the Figure object (to which mpf.plot() has no access in external axes mode) or if it involves the relationship between the Axes objects and the Figure object.

From what you have written, it is also not completely clear what you are trying to accomplish: your comment says

I simply want to remove the box surrounding the figures

but the code is attempting to remove the box around the Axes (not the Figures).

Assuming the code is the ultimate documentation, try using mpf.plot(data,...,axisoff=True) or, alternatively, since you have control of the axes objects, you can call Axes.set_axis_off() yourself. (Correction: I just realized kwarg axisoff=True does not work in external axes mode: as can be seen here, in external axes mode mpf.plot() returns before the axisoff code is reached.).

If that doesn't do it for you, and you have further questions, it would be helpful if I could see the rest of your code.

All the best. --Daniel

pipreaper commented 3 years ago

Yes ... I see ... It is the figure I am trying to remove the bounding box/black frame from. but a call to mpf gives an interpreter error:

File "/home/rob/PycharmProjects/get_prospects/Main/Pages/Page1/Page1.py", line 412, in draw_renko self.fig_renko.spines['bottom'].set_linewidth(12.5) AttributeError: 'Mpf_Figure' object has no attribute 'spines'

when I call:

    def draw_renko(self):
        try:
            if self.controller.show_renko:
                if self.controller.renko_ohlc_show_boxes and self.controller.show_ohlc:
                    draw_ohlc_boxes(self, self.ohlc_axis)
                    self.canvas_ohlc.draw()
                draw_renko_boxes(self, self.renko_axis)
                self.fig_renko.suptitle(
                    'Renko: ' + remove(self.controller.ticker_symbol) + ', Period: ' + self.controller.interval + ' , Box Size:' + self.formatted_brick_size, fontsize=8)
                self.renko_axis.axes.xaxis.set_visible(False)
                self.renko_axis.set_ylabel('')
                self.renko_axis.set_facecolor(chart_face_color)
                self.renko_axis.tick_params(axis='y', labelsize=chart_y_font_size)  # ,  top='off', bottom='off', left='off', right='off')  # , top='off', bottom='off', left='off', right='off',
                # labelleft='on', labelbottom='on')
                self.renko_axis.tick_params(axis='x', labelsize=chart_y_font_size)  #  , top='off', bottom='off', left='off', right='off')  # , labelleft='on', labelbottom='on')

                # self.fig_renko.tick_params(axis='x', top='off', bottom='off', left='off', right='off')
                # self.renko_axis.spines['top'].set_visible(False)
                # self.renko_axis.spines['right'].set_visible(False)
                # self.renko_axis.spines['left'].set_visible(False)
                # self.renko_axis.spines['bottom'].set_visible(False)
                # self.renko_axis.spines['bottom'].set_linewidth(2.5)
                # self.renko_axis.spines['left'].set_linewidth(2.5)
                # self.renko_axis.spines['bottom'].set_color('pink')
                # self.renko_axis.spines['left'].set_color('pink')
                # self.renko_axis.set_edge_color("white")
                # self.fig_renko.set_edgecolor("white")
                # self.renko_axis.set_frame_on(False)
                # self.renko_axis.tick_params(top='off', bottom='off', left='off', right='off', labelleft='off', labelbottom='on')

                self.fig_renko.spines['bottom'].set_linewidth(12.5)
                self.fig_renko.spines['left'].set_linewidth(12.5)
                self.fig_renko.spines['bottom'].set_color('blue')
                self.fig_renko.spines['left'].set_color('blue')

                self.canvas_renko.draw()
        except Exception as e:
            logger.exception(e)
pipreaper commented 3 years ago

How can I access spines from mpf. ? do I attempt to use kwangs is there another method?

pipreaper commented 3 years ago

I have code I can try and make an example but it wouldnt be any cleaner than what I have. I have attached the Page file for plot.

from tkinter import Frame

import mplfinance as mpf
import talib
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk

from Generate_signals.RenkoSignals import RenkoBricks
from Main.FetchYahoo import get_ticker_history
from Main.Indicators.BaseIndicator import BaseIndicator
from Main.Indicators.OHLCIndicators import OHLCBaseIndicator, calc_renko_high_close
from Main.Indicators.RenkoIndicators import RenkoBaseIndicator
from Main.Pages.Page1.page1_assist_functions import *
from Main.Pages.basePage import BasePage
from Main.get_my_logger import logging
from Utilities.use_funcs import remove
from Main.defaults import chart_face_color, chart_y_font_size, chart_bounding_line_width, chart_font_axis_color, chart_outer_box_color
from styles.my_styles import my_style

logger = logging.getLogger(__name__)

class PageOne(BasePage):

    def __init__(self, controller):
        BasePage.__init__(self, controller, '1: Plot')
        # df_ohlc = pd.DataFrame()

        try:
            self.last_atr = -1
            self.yahoo_data = pd.DataFrame()
            self.renko_data = pd.DataFrame()

            # CANVASES
            self.frame_canvases = None

            # OHLC
            self.frame_canvas_ohlc = None
            self.frame_nav_ohlc = None
            self.fig_ohlc = None
            self.canvas_ohlc = None
            self.toolbar_ohlc = None
            self.ohlc_axis = None
            self.ohlc_chart_loc = 0  # default for no ohlc chart displayed ... otherwise set to 1 (display)

            # RENKO
            self.frame_canvas_renko = None
            self.frame_nav_renko = None
            self.fig_renko = None
            self.renko_axis = None
            self.canvas_renko = None
            self.toolbar_renko = None
            self.kwargs_ohlc = {}

            # AXIS
            self.axis_list_rsi = None
            self.axis_list_stochs = None
            self.unique_index = None
            self.x_num_index_ohlc = None
            self.x_num_index_renko = None

            # SUNDRY
            self.my_ich = None
            self.formatted_brick_size = -1
            self.box_calc = -1
            self.width_of_plot = -1

            logger.info('initialised')
        except Exception as e:
            # print(e.args)
            logger.exception('exception: ')

    def define_layout(self):
        try:
            if self.frame_canvases is not None:
                clear_frame(self.frame_canvases)
            # create MASTER canvas frame
            self.frame_canvases = Frame(self.frame_main, borderwidth=10, bg='black')

            if self.controller.show_ohlc:
                # create OHLC canvas frame
                self.frame_canvas_ohlc = Frame(self.frame_canvases, borderwidth=10, bg='pink')

                # create mpf figure
                self.fig_ohlc = mpf.figure(figsize=(18, 17))
                OHLCBaseIndicator.set_grid_spec(self.fig_ohlc)

                # define ohlc axis
                self.ohlc_axis = self.fig_ohlc.add_subplot(OHLCBaseIndicator.spec[0, 0])
                # self.ohlc_axis = self.fig_ohlc.add_subplot(OHLCBaseIndicator.total_panel_rows, OHLCBaseIndicator.num_columns, 1)

                # create OHLC canvas
                self.canvas_ohlc = FigureCanvasTkAgg(self.fig_ohlc, self.frame_canvas_ohlc)

                # toolbar OHLC
                # self.frame_nav_ohlc = Frame(self.frame_canvases, borderwidth=10, bg='blue')
                self.toolbar_ohlc = NavigationToolbar2Tk(self.canvas_ohlc, self.frame_canvases, pack_toolbar=False)
                self.toolbar_ohlc.update()

            if self.controller.show_renko:
                # create a RENKO canvas frame
                self.frame_canvas_renko = Frame(self.frame_canvases, borderwidth=10, bg='green')

                # create a renko figure
                self.fig_renko = mpf.figure(figsize=(18, 17), edgecolor=None)
                RenkoBaseIndicator.set_grid_spec(self.fig_renko)

                # define renko axis
                self.renko_axis = self.fig_renko.add_subplot(RenkoBaseIndicator.spec[0, 0])
                # self.renko_axis = self.fig_renko.add_subplot(RenkoBaseIndicator.total_panel_rows, RenkoBaseIndicator.num_columns, 1)

                # create renko canvas
                self.canvas_renko = FigureCanvasTkAgg(self.fig_renko, self.frame_canvas_renko)

                # toolbar renko
                # self.frame_nav_renko = Frame(self.frame_canvases, borderwidth=10, bg='red')
                self.toolbar_renko = NavigationToolbar2Tk(self.canvas_renko, self.frame_canvases, pack_toolbar=False)

            logger.info('initialised')
        except Exception as e:
            # print(e.args)
            logger.exception('exception: ')
            pass
        finally:
            pass

    def define_position_layout(self):
        # position of frame_canvases in frame_main col = 1 because menu always in 0
        self.frame_canvases.grid(row=0, column=1, sticky='nsew')
        row_id = -1

        # decide what to plot where because navigation does not scale
        if self.controller.show_ohlc and self.controller.show_renko:
            self.frame_canvases.rowconfigure(0, weight=1)
            self.frame_canvases.rowconfigure(2, weight=1)
            self.frame_canvases.columnconfigure(0, weight=1)
        elif self.controller.show_ohlc or self.controller.show_renko:
            self.frame_canvases.rowconfigure(0, weight=1)
            self.frame_canvases.columnconfigure(0, weight=1)

        if self.controller.show_ohlc:
            # create OHLC canvas frame
            row_id += 1
            self.frame_canvas_ohlc.grid(row=row_id, column=0, sticky='nsew')
            self.frame_canvas_ohlc.rowconfigure(0, weight=1)
            self.frame_canvas_ohlc.columnconfigure(0, weight=1)
            # get ohlc canvas so can draw later
            self.canvas_ohlc.get_tk_widget().grid(row=0, column=0)

            # define nav ohlc
            row_id += 1
            # self.frame_nav_ohlc.grid(row=row_id, column=0, sticky='nsew')
            self.toolbar_ohlc.grid(row=row_id, column=0, sticky='nsew')

        if self.controller.show_renko:
            # define renko canvas frame
            row_id += 1
            self.frame_canvas_renko.grid(row=row_id, column=0, sticky='nsew')
            self.frame_canvas_renko.rowconfigure(0, weight=1)
            self.frame_canvas_renko.columnconfigure(0, weight=1)
            # get renko canvas so can draw later
            self.canvas_renko.get_tk_widget().grid(row=0, column=0)

            # define renko nav
            row_id += 1
            self.toolbar_renko.grid(row=row_id, column=0, sticky='nsew')

        # draw canvases
        # self.canvas_ohlc.draw()
        # self.toolbar_ohlc.update()
        # self.canvas_renko.draw()
        # self.toolbar_renko.update()

    def plot_me(self):
        try:
            set_ticker_to_plot(self)
            self.define_layout()
            self.define_position_layout()
            self.yahoo_data = get_ticker_history(self.controller.ticker, self.controller.start, self.controller.end, self.controller.interval)
            if self.yahoo_data.empty:
                raise ValueError("failed to get ticker history:", self.controller.ticker_symbol, self.controller.start, self.controller.end,
                                 self.controller.interval)
            else:
                OHLCBaseIndicator.add_plots = []
                RenkoBaseIndicator.add_plots = []
                if self.controller.interval == 'D':
                    self.yahoo_data = self.yahoo_data[self.yahoo_data.index.dayofweek < 5]  # remove weekends but not holidays!
                self.define_renko_bricks_goldfarb()  # get renko associated data
                self.define_ohlc_charts_data()  # define chart data and indicator plots required
                self.generate_renko_signals()  # find double bottoms if exist
                self.create_ohlc_indicators()  # indicators for ohlc plot
                self.draw_chart_ohlc()
                self.create_main_ohlc_cursor()  # create the cursors to match the required plot
                self.create_ohlc_indicator_cursors()  # create any cursors indicators have
                self.get_high_low_renko()  # get the high and low values for renko bricks to be used in renko indicators
                self.create_renko_chart_indexing()  # use Goldfarb bricks to define your own plot if renko required
                self.create_renko_indicators()  # create ichimoku ++
                self.create_main_renko_cursor()  # create renko cursor
                self.create_renko_indicator_cursors()  # create indicator cursors
                self.draw_renko()  # display the renko chart and indicators
        except ValueError as e:
            self.canvas_renko.draw()
            logger.warning(e)
        except Exception as e:
            logger.exception(e)

    def define_renko_bricks_goldfarb(self):
        try:
            renko_atr = (talib.ATR(self.yahoo_data['High'], self.yahoo_data['Low'], self.yahoo_data['Close'], self.controller.renko_atr_period))
            # # print(df_rsi)
            lst_atr = renko_atr.values.tolist()
            self.last_atr = lst_atr[-1]  # renko_atr.mean()
            self.box_calc = self.controller.renko_box_calc * self.last_atr

            self.formatted_brick_size = "BrickSize : {:.2f}".format(self.box_calc)
            # check can calculate bricks
            close_range = self.yahoo_data['Close'].max() - self.yahoo_data['Close'].min()
            # if self.controller.ticker.strip() == 'CPG.L': logger.warning('atr period = '+str(self.controller.renko_atr_period)+' lst_atr '+str(
            # self.last_atr) + ' box_calc ' + str(box_calc) + ' close range ' + str(close_range)) check for Nan in data sets
            if self.box_calc >= 0.5 * close_range:
                raise Exception(' Specified brick_size: ', self.formatted_brick_size,
                                ' may not be larger than (50% of the close price range of the dataset) which has value: ', close_range)

            # use Goldfarb to get the bricks then ignore:
            ret_data = {}
            kwargs_renko = dict(axisoff=False, xrotation=20, type='renko',
                                renko_params=dict(brick_size=self.box_calc), ylabel='price', tight_layout=False,
                                datetime_format="%d-%m-%Y", return_calculated_values=ret_data, returnfig=True, closefig=True,
                                ylim=(self.yahoo_data.Low.min(), self.yahoo_data.High.max()))
            dum_fig, ax = mpf.plot(self.yahoo_data, **kwargs_renko, mav=[9], volume=True)
            # get the class that holds the renko Bricks data
            self.renko_data = RenkoBricks(self.controller.script_directory, self.controller.data_directory)
            self.renko_data.set_brick_info(self.controller.ticker, ret_data, self.yahoo_data)
            ax[0].cla()
            # don't need Goldfarb for renko plots after have initial bricks because of issues plotting indicators viz/. Ichimoku
            # dum_fig = None
        except Exception as e:
            logger.exception(e)
            pass

    def define_ohlc_charts_data(self):
        """
            read yahoo series
        """
        try:
            # if self.controller.ticker.strip() == 'CPG.L':
            #     self.write_csv(self.yahoo_data, 'page1_yahoo', self.controller.script_directory, self.controller.config_directory)
            self.yahoo_data = self.yahoo_data.tz_localize('UTC')
            # generate the signals in the bricks df
            self.yahoo_data['db_sig'] = np.nan  # set signals to False
            self.yahoo_data['db_low'] = np.nan
            self.yahoo_data['Date'] = pd.to_datetime(self.yahoo_data.index)
        except Exception as e:
            logger.exception('failed to calculate the renko bricks as a function of atr: ')

    def generate_renko_signals(self):
        try:
            if self.controller.show_renko:
                if self.renko_data.Pivots.set_pivots_signal():
                    logger.info(' have pivots for double bottom: ')
                    self.renko_data.Pivots.print_pivot()
                    self.yahoo_data = self.renko_data.set_markers()
        except Exception as e:
            logger.exception('failed to create renko signals: ')

    def create_ohlc_indicators(self):
        """from selected classes populate indicators"""
        try:
            if self.controller.show_ohlc:
                # loop around indicators created creating the plots from the data
                for index in range(len(OHLCBaseIndicator.indicators)):
                    d = OHLCBaseIndicator.indicators[index]
                    d.yahoo_data = self.yahoo_data
                    self.yahoo_data = d.my_add_plots(self)
        except Exception as e:
            logger.exception(e)

    def draw_chart_ohlc(self):
        try:
            if self.controller.show_ohlc:

                # my_rc ={}  #  {'font.size': 20}
                s = mpf.make_mpf_style(base_mpf_style='charles', y_on_right=False)  #, rc=my_rc)

                trm = remove(self.controller.ticker_symbol)
                trm = 'OHLC: ' + trm + ', Period: ' + self.controller.interval
                self.fig_ohlc.suptitle(trm, fontsize=8)
                self.kwargs_ohlc = dict(xrotation=20, type='candle',
                                        ylabel='', datetime_format="%d-%m-%Y",
                                        returnfig=True,
                                        closefig=True)
                dict(self.kwargs_ohlc, ylim=(self.yahoo_data.Low.min(), self.yahoo_data.High.max()))
                if self.controller.ohlc_show_ichimoku:
                    fill_in = dict(y1=self.yahoo_data.senkou_span_a.values, y2=self.yahoo_data.senkou_span_b.values, alpha=1, color='black')
                    dict(self.kwargs_ohlc, fill_between=fill_in)
                self.ohlc_axis.set_facecolor(chart_face_color)
                self.ohlc_axis.tick_params(axis='y', labelsize=chart_y_font_size, colors=chart_font_axis_color)
                self.ohlc_axis.tick_params(axis='x', labelsize=chart_y_font_size, colors=chart_font_axis_color)
                mpf.plot(self.yahoo_data, ax=self.ohlc_axis, addplot=OHLCBaseIndicator.add_plots, **self.kwargs_ohlc)

                # number index is need for the cursor position, x axis is mapped with integer first and converted to date later
                self.x_num_index_ohlc = np.arange(0, len(self.yahoo_data['Close']), 1)
                self.unique_index = pd.Index(self.yahoo_data.index)
                self.canvas_ohlc.draw()
        except Exception as e:
            logger.exception(e)

    def create_main_ohlc_cursor(self):
        """ ohlc bar chart cursor """
        try:
            if self.controller.show_ohlc:
                num_dec_places = 2  # set according to instrument being displayed
                s_num_dec_plc = str(num_dec_places)
                output_dict = {'Date': 'Date  {0}\n',
                               'Price': 'Price {1:.' + s_num_dec_plc + 'f}\n',
                               'Open': 'Open  {2:.' + s_num_dec_plc + 'f}\n',
                               'High': 'High  {3:.' + s_num_dec_plc + 'f}\n',
                               'Low': 'Low  {4:.' + s_num_dec_plc + 'f}\n',
                               'Close': 'Close {5:.' + s_num_dec_plc + 'f}\n'
                               }
                create_ohlc_cursor(self, self.canvas_ohlc, self.ohlc_axis, output_dict, self.yahoo_data, self.x_num_index_ohlc, 'black', 0.5)
        except Exception as e:
            logger.exception(e)

    def create_ohlc_indicator_cursors(self):
        """from selected classes populate cursors"""
        try:
            if self.controller.show_ohlc:
                # loop around indicators created creating the plots from the data
                for index in range(len(OHLCBaseIndicator.indicators)):
                    d = OHLCBaseIndicator.indicators[index]
                    d.create_cursor(self)
        except Exception as e:
            logger.exception(e)

    def get_high_low_renko(self):
        """ get transformed data. Needs to kn ow high and close for ichimoku renko"""
        if self.controller.show_renko:
            self.renko_data.bricks_df = calc_renko_high_close(self.renko_data.bricks_df, self.yahoo_data, self.renko_data.brick_size)

    def create_renko_chart_indexing(self):
        try:
            if self.controller.show_renko:
                self.x_num_index_renko = np.arange(0, len(self.renko_data.get_bricks_df()['renko_bricks_low']), 1)
        except ValueError as e:
            logger.warning(e)
        except Exception as e:
            logger.exception(e)
            pass

    def create_renko_indicators(self):
        """from selected classes populate renko indicators"""
        try:
            if self.controller.show_renko:
                # loop around indicators created creating the plots from the data
                for index in range(len(RenkoBaseIndicator.indicators)):
                    d = RenkoBaseIndicator.indicators[index]
                    d.renko_data = self.renko_data
                    self.renko_data = d.my_add_plots(self)
        except Exception as e:
            logger.exception(e)

    def create_main_renko_cursor(self):
        try:
            if self.controller.show_renko:
                num_dec_places = 2  # set according to instrument being displayed
                s_num_dec_plc = str(num_dec_places)
                output_dict = {'end_date': 'end_date  {0}\n', 'renko_bricks_low': 'renko_bricks_low {1:.' + s_num_dec_plc + 'f}\n'}
                renko_snap_hairs(self, self.canvas_renko, self.renko_axis, output_dict, self.renko_data.bricks_df, self.x_num_index_renko, 'black', 0.5)
        except Exception as e:
            logger.exception(e)

    def create_renko_indicator_cursors(self):
        """from selected classes populate renko cursors"""
        try:
            if self.controller.show_renko:
                # loop around indicators created creating the plots from the data
                for index in range(len(RenkoBaseIndicator.indicators)):
                    d = RenkoBaseIndicator.indicators[index]
                    d.create_cursor(self)
        except Exception as e:
            logger.exception(e)

    def draw_renko(self):
        try:
            if self.controller.show_renko:
                if self.controller.renko_ohlc_show_boxes and self.controller.show_ohlc:
                    draw_ohlc_boxes(self, self.ohlc_axis)
                    self.canvas_ohlc.draw()
                draw_renko_boxes(self, self.renko_axis)
                self.fig_renko.suptitle(
                    'Renko: ' + remove(self.controller.ticker_symbol) + ', Period: ' + self.controller.interval + ' , Box Size:' + self.formatted_brick_size, fontsize=8)
                self.renko_axis.axes.xaxis.set_visible(False)
                self.renko_axis.set_ylabel('')
                self.renko_axis.set_facecolor(chart_face_color)
                self.renko_axis.tick_params(axis='y', labelsize=chart_y_font_size)  # ,  top='off', bottom='off', left='off', right='off')  # , top='off', bottom='off', left='off', right='off',
                # labelleft='on', labelbottom='on')
                self.renko_axis.tick_params(axis='x', labelsize=chart_y_font_size)  #  , top='off', bottom='off', left='off', right='off')  # , labelleft='on', labelbottom='on')

                # self.fig_renko.tick_params(axis='x', top='off', bottom='off', left='off', right='off')
                # self.renko_axis.spines['top'].set_visible(False)
                # self.renko_axis.spines['right'].set_visible(False)
                # self.renko_axis.spines['left'].set_visible(False)
                # self.renko_axis.spines['bottom'].set_visible(False)
                # self.renko_axis.spines['bottom'].set_linewidth(2.5)
                # self.renko_axis.spines['left'].set_linewidth(2.5)
                # self.renko_axis.spines['bottom'].set_color('pink')
                # self.renko_axis.spines['left'].set_color('pink')
                # self.renko_axis.set_edge_color("white")
                # self.fig_renko.set_edgecolor("white")
                # self.renko_axis.set_frame_on(False)
                # self.renko_axis.tick_params(top='off', bottom='off', left='off', right='off', labelleft='off', labelbottom='on')
                self.fig_renko.spines['bottom'].set_linewidth(12.5)
                self.fig_renko.spines['left'].set_linewidth(12.5)
                self.fig_renko.spines['bottom'].set_color('blue')
                self.fig_renko.spines['left'].set_color('blue')
                self.canvas_renko.draw()
        except Exception as e:
            logger.exception(e)
pipreaper commented 3 years ago

hope it gives a better understanding of what Im trying to do. Any comments welcome.

DanielGoldfarb commented 3 years ago

How can I access spines from mpf. ? do I attempt to use kwangs is there another method?

spines are an attribute of Axes, not of Figure. The class MpfFigure is derived from Matplotlib.figure.Figure and so it does contain all of the same attributes as a matplotlib Figure. but spines is not one of them.

I will try to make time later today to look through your code and see if I have any suggestions.

Thank you. --Daniel

DanielGoldfarb commented 3 years ago

Hi @pipreaper I don't have time to go through your code in a lot of detail, but I did glance through it and I have a few comments that may be of some help:

First and foremost, it appears that you are mixing the ideas of returnfig and external axes mode.
For example, I see you calling mpf.figure() to create a figure, but elsewhere calling
dum_fig, ax = mpf.plot(...,returnfig=True)
(and in draw_chart_ohlc() you have set returnfig=True but are altogether ignoring the Figure and Axes returned from mpf.plot()).

Be aware that when you set returnfig=True then mpf.plot() will create both the FIgure and Axes objects for you and return them to you. *Those Axes objects are therefore not on the same Figure object that you have created separately with mpf.figure() (unless you specifically add them to that Figure object yourself)*.

There is documentation here with links to additional documentaion that explain the difference between returnfig=True and external Axes mode.

As a general rule I discourage external axes mode. You could change your code to go either way, but it is definitely not a good idea to try to mix them: The one exception (to mixing them) is when you call mpf.plot(...,returnfig=True) once only, save the Figure and Axes list returned, and then pass those Axes back into mpf.plot() for all subsequent calls to mpf.plot().

That said, looking over your code, however, I am inclined to say *I think will be easier to convert your code to use only external axes mode*. You are already saving (inside your own classes) the Figure and Axes that you created yourself with mpf.figure() and self.fig_renko.add_subplot(RenkoBaseIndicator.spec[0, 0]). And you are also alreading doing a lot of matplotlib manipulation of these objects anyway. You might as well use only these external Figure and Axes, and pass your Axes objects into mpf.plot() with kwarg ax= ... maybe something like mpf.plot(...,ax=self.renko_axis,...).

Finally, it's still not completely clear to me which frame you are trying to eliminate. Perhaps take this image and edit it with an image editor or drawing program, placing arrows on the image pointing to the exact frame(s) you want to eliminate. It occurs to me that it is possible that some of the frames are actually part of tkinter and not necessarily part of matplotlib.

All the best.

pipreaper commented 3 years ago

I will work it out and post when I find solution. I think its associated with self.fig_ohlc having default rc values. gold_2

pipreaper commented 3 years ago

Yes so solution is to add edge color to the figures -> axes.edgecolor.

gold_4 gold 3

Many thanks and sorry to bother you. Just had a moment where I didn't realise that the figure had axes settings too

pipreaper commented 3 years ago

Hi @pipreaper I don't have time to go through your code in a lot of detail, but I did glance through it and I have a few comments that may be of some help:

First and foremost, it appears that you are mixing the ideas of returnfig and external axes mode. For example, I see you calling mpf.figure() to create a figure, but elsewhere calling dum_fig, ax = mpf.plot(...,returnfig=True) (and in draw_chart_ohlc() you have set returnfig=True but are altogether ignoring the Figure and Axes returned from mpf.plot()).

Be aware that when you set returnfig=True then mpf.plot() will create both the FIgure and Axes objects for you and return them to you. Those Axes objects are therefore not on the same Figure object that you have created separately with mpf.figure() (unless you specifically add them to that Figure object yourself).

There is documentation here with links to additional documentaion that explain the difference between returnfig=True and external Axes mode.

As a general rule I discourage external axes mode. You could change your code to go either way, but it is definitely not a good idea to try to mix them: The one exception (to mixing them) is when you call mpf.plot(...,returnfig=True) once only, save the Figure and Axes list returned, and then pass those Axes back into mpf.plot() for all subsequent calls to mpf.plot().

That said, looking over your code, however, I am inclined to say I think will be easier to convert your code to use only external axes mode. You are already saving (inside your own classes) the Figure and Axes that you created yourself with mpf.figure() and self.fig_renko.add_subplot(RenkoBaseIndicator.spec[0, 0]). And you are also alreading doing a lot of matplotlib manipulation of these objects anyway. You might as well use only these external Figure and Axes, and pass your Axes objects into mpf.plot() with kwarg ax= ... maybe something like mpf.plot(...,ax=self.renko_axis,...).

Finally, it's still not completely clear to me which frame you are trying to eliminate. Perhaps take this image and edit it with an image editor or drawing program, placing arrows on the image pointing to the exact frame(s) you want to eliminate. It occurs to me that it is possible that some of the frames are actually part of tkinter and not necessarily part of matplotlib.

All the best.

Thank you so much for taking the time to look at the code.

wrt your comments:

1/. I use dum_fig, ax = mpf.plot(...,returnfig=True) to return mplfinance volume and brick information but do not want to plot it as (rightly or wrongly), I needed more control over the axis for cursor manipulation and indicator plotting (could not  see a way to use fill with mplfinance to get different colors I wanted to see on Ichimoku). Returning a fig and an axis that I was never going to use was the only way I could see to do this whilst having the convenience of not having to calculate the volume and brick information by other means. I also pull this same information for many instruments when looping around the algo for instrument selection .... If there is another way of getting your information on bricks and volume whilst using my own external axes I would be grateful to know it so please advise.

2/. Yes I see what I was doing in draw_chart_ohlc was incorrect. Many thanks. I have now removed returnfig=True, closefig=True from the kwarg list past to the mpf.plot(...).

3/. What I was trying to do ... please see explanation above. where the axes are now bounded in blue with the code changes highlighted in the code editor.