Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Adjust a panel's x_lim and title padding #212

Closed
twopirllc opened this issue Jul 8, 2020 · 12 comments
Closed

Feature Request: Adjust a panel's x_lim and title padding #212

twopirllc opened this issue Jul 8, 2020 · 12 comments
Labels
enhancement New feature or request released code merged into repo AND released to Pypi

Comments

@twopirllc
Copy link

Hello @DanielGoldfarb,

Thanks for reviving mplfinance and making it better! I like the new panel additions. They are awesome!

Is your feature request related to a problem? Please describe.
I was able to target mpf.make_addplot(ylim: tuple)) to adjust a panel's top and bottom ylim's so the panel's are not too close. Is it possible to at least set xlim=(mpf.minx, 0.9 * mpf.max)?

The bottom padding for title seems large. Possible bug? 🤷 Where self.title = "SPY (D)".

Here is the heart of the mpf plot code for the chart below:

mpf_style = mpf.make_mpf_style(base_mpf_style=mpf_styles[-1], rc={'figure.facecolor': '#EDEDED'})
width_config={'candle_linewidth':0.8, 'candle_width':0.525, 'volume_width': 0.525}

mpf.plot(
    self.df.tail(self.recent), type="candle", title=self.title,
    style=mpf_style, datetime_format="%-m - %-d - %Y",
    volume=True, addplot=priceta + volta + rsita,
    figsize=(16, 8), panel_ratios=(1, 0.2, .4), xrotation=32,
    update_width_config=width_config
)

Screen Shot 2020-07-07 at 11 28 00 PM

Describe the solution you'd like
Ideally, I would like the ability to adjust at least the left padding of each panel. Or a tight_layout with an adjustable right padding for each panel.

Thanks for your time,
KJ

@twopirllc twopirllc added the enhancement New feature or request label Jul 8, 2020
@DanielGoldfarb
Copy link
Collaborator

DanielGoldfarb commented Jul 8, 2020

Kevin,

First l'd like to say that's a great looking plot. I like what you've done with mplfinance: creative and useful.

Please try setting tight_layout=True in the call to mpf.plot( ) and let me know how that works for you. That should automatically adjust your x-axis limits, and should also fix the extra padding around the title at the top of the Figure ("SPY (D)") by placing the title slightly lower and decreasing the padding somewhat.

Beyond that, there are two ways that you can adjust the Figure padding surround the panels. It cannot be done per-panel, because by definition the panels are all the same width, and the padding relates to the Figure as a whole.

mpf.plot( ) has a kwarg scale_padding which can be set in one of two ways:

  • scale_padding=<number> where number is an integer or float greater than or less than 1.0 to either increase or decrease the amount of padding around all four sides of the Figure.
  • scale_padding=<dict> where dict contains one or more of the following keys: left, right, top, bottom and the value associated with the key is an integer or float greater than or less than 1.0 to either increase or decrease the amount of padding on the side of the Figure indicated by the dict key(s).

Please note: tight_layout and scale_padding are independent of each other, so you can use one or both, and they will each apply the effect they were coded to apply. Both will affect the padding, but only tight_layout will also affect the x-axis limits and the placement of the Figure title.

HTH. All the best. --Daniel

@twopirllc
Copy link
Author

Hi Daniel,

Thank you for the suggestions. Here are some of my results:

Using tight_layout

mpf_style = mpf.make_mpf_style(base_mpf_style=mpf_styles[-1], rc={'figure.facecolor': '#EDEDED'})
width_config={'candle_linewidth':0.8, 'candle_width':0.525, 'volume_width': 0.525}

mpf.plot(
    self.df.tail(self.recent), type="candle", title=self.title,
    style=mpf_style, datetime_format="%-m - %-d - %Y",
    volume=True, addplot=priceta + volta + rsita,
    figsize=(16, 8), panel_ratios=(1, 0.1, .2), xrotation=32,
    update_width_config=width_config, tight_layout=True
)

yields the following:

Screen Shot 2020-07-08 at 9 52 10 AM

Using tight_layout and scale_padding

So scale_padding.top = 5 helped adjust the title. Whereas scale_padding.left != 1 and scale_padding.right != 1 yield no meaningful results.

mpf_style = mpf.make_mpf_style(base_mpf_style=mpf_styles[-1], rc={'figure.facecolor': '#EDEDED'})
width_config={'candle_linewidth':0.8, 'candle_width':0.525, 'volume_width': 0.525}

mpf.plot(
    self.df.tail(self.recent), type="candle", title=self.title,
    style=mpf_style, datetime_format="%-m - %-d - %Y",
    volume=True, addplot=priceta + volta + rsita,
    figsize=(16, 8), scale_padding={'left': 1, 'top': 5, 'right': 1, 'bottom': 1},
    panel_ratios=(1, 0.2, .4), xrotation=32,
    update_width_config=width_config, tight_layout=True,
)

yields the following:

Screen Shot 2020-07-08 at 11 11 02 AM

That helps. That is the closest I can get to desired output, so I'll run with it. I am gonna refactor some code add it to my repo's example notebook.

Thanks again!
KJ

@DanielGoldfarb
Copy link
Collaborator

Thank you for posting your results.

Not sure why scale_padding.left != 1 and scale_padding.right != 1 are ineffective. It could be that tight_layout scales them down so much that you would need to either:

(a) try scale_padding without tight_layout, or
(b) make left and right padding significantly more than 1.0 to counteract the downscaling of padding by tight_layout.

Please try both (a) and (b) and let me know how it looks.
I will also consider adding a kwarg to adjust xlimits, since presently the only way to adjust xlimits is via tight_layout.

Thanks. --Daniel

@twopirllc
Copy link
Author

Below are my results:

# static vars
df = self.df.tail(self.recent)
mpf_style = mpf.make_mpf_style(base_mpf_style=mpf_styles[-1], rc={'figure.facecolor': '#EDEDED'})
width_config={'candle_linewidth':0.8, 'candle_width':0.525, 'volume_width': 0.525}

(A) scale_padding without tight_layout:

(1) scale_padding.left=4 and tight_layout=False:

mpf.plot(
    df, type="candle", title=self.title,
    style=mpf_style, datetime_format="%-m - %-d - %Y",
    volume=True, addplot=priceta + volta + rsita,
    figsize=(12, 10), scale_padding={'left': 4, 'top': 1, 'right': 1, 'bottom': 1},
    panel_ratios=pratios, xrotation=32,
    update_width_config=width_config, tight_layout=False,
)

yields:
Screen Shot 2020-07-08 at 2 56 00 PM

(2) scale_padding.right=4 and tight_layout=False:

mpf.plot(
    df, type="candle", title=self.title,
    style=mpf_style, datetime_format="%-m - %-d - %Y",
    volume=True, addplot=priceta + volta + rsita,
    figsize=(12, 10), scale_padding={'left': 1, 'top': 1, 'right': 4, 'bottom': 1},
    panel_ratios=pratios, xrotation=32,
    update_width_config=width_config, tight_layout=False,
)

yields:
Screen Shot 2020-07-08 at 2 57 54 PM

(3) scale_padding.left=4 and scale_padding.right=4 and tight_layout=False:

mpf.plot(
    df, type="candle", title=self.title,
    style=mpf_style, datetime_format="%-m - %-d - %Y",
    volume=True, addplot=priceta + volta + rsita,
    figsize=(12, 10), scale_padding={'left': 4, 'top': 1, 'right': 4, 'bottom': 1},
    panel_ratios=pratios, xrotation=32,
    update_width_config=width_config, tight_layout=False,
)

yields:

Width and height specified must be non-negative
<Figure size 1200x1000 with 0 Axes>

(4) scale_padding.left=2 and scale_padding.right=2 and tight_layout=False:

mpf.plot(
    df, type="candle", title=self.title,
    style=mpf_style, datetime_format="%-m - %-d - %Y",
    volume=True, addplot=priceta + volta + rsita,
    figsize=(12, 10), scale_padding={'left': 2, 'top': 1, 'right': 2, 'bottom': 1},
    panel_ratios=pratios, xrotation=32,
    update_width_config=width_config, tight_layout=False,
)

yields:
Screen Shot 2020-07-08 at 3 01 27 PM

(B) scale_padding.left >> 1 and scale_padding.right >> 1 with tight_layout:

(1) scale_padding.left=4 and scale_padding.right=4 and tight_layout=True:

mpf.plot(
    df, type="candle", title=self.title,
    style=mpf_style, datetime_format="%-m - %-d - %Y",
    volume=True, addplot=priceta + volta + rsita,
    figsize=(12, 10), scale_padding={'left': 4, 'top': 1, 'right': 4, 'bottom': 1},
    panel_ratios=pratios, xrotation=32,
    update_width_config=width_config, tight_layout=True,
)

yields:
Screen Shot 2020-07-08 at 3 05 15 PM

(2) scale_padding.left=2 and scale_padding.right=2 and tight_layout=True:

mpf.plot(
    df, type="candle", title=self.title,
    style=mpf_style, datetime_format="%-m - %-d - %Y",
    volume=True, addplot=priceta + volta + rsita,
    figsize=(12, 10), scale_padding={'left': 2, 'top': 1, 'right': 2, 'bottom': 1},
    panel_ratios=pratios, xrotation=32,
    update_width_config=width_config, tight_layout=True,
)

yields:
Screen Shot 2020-07-08 at 3 09 18 PM

Hope this helps!

Thank you,
KJ

@DanielGoldfarb
Copy link
Collaborator

Thanks. Are any of those even close to what you are trying to accomplish? Perhaps the last one (except for maybe the exact placement of the Title)?

I just want to point out that I had never really intended to publicize scale_padding, but I am glad if it is helping. The intention was that scale_padding was a temporary kwarg to help me experiment while developing tight_layout. Afterwards I decided to leave the kwarg in place, "just in case" it might be useful for someone.

@twopirllc
Copy link
Author

Sure.

Are any of those even close to what you are trying to accomplish?

Not any of the previous tests. This version is the closest:

df = self.df.tail(self.recent)
mpf_style = mpf.make_mpf_style(base_mpf_style=mpf_styles[-1], rc={'figure.facecolor': '#EDEDED'})
width_config={'candle_linewidth':0.8, 'candle_width':0.525, 'volume_width': 0.525}

mpf.plot(
    df, type="candle", title=self.title,
    style=mpf_style, datetime_format="%-m - %-d - %Y",
    volume=True, addplot=priceta + volta + rsita + zscoreta,
    figsize=(12, 10), scale_padding={'left': 1, 'top': 4, 'right': 1, 'bottom': 1},
    panel_ratios=pratios, xrotation=32,
    update_width_config=width_config, tight_layout=True,
)

yielding:
Screen Shot 2020-07-08 at 7 46 14 PM

Ideally, there is adjustable padding/margin in the orange zone just like when tight_layout=False. Everything in the orange zone would be shifted left so there is some space to the right.

chart example padding

Hope this make sense.

Thanks for your time,
KJ

@DanielGoldfarb
Copy link
Collaborator

Thank you. That makes sense. Until we have a xlimit kwarg, you can add some padding on the right side as follows:

dfpad = df.tail(7).copy()
dfpad.loc[:,:] = float('nan')
newdf = df.append(dfpad)

mpf.plot(newdf,...)

To adjust the amount of padding, modify the number you pass into df.tail()
And don't forget to add .copy() otherwise the nans may affect the original dataframe.

When I do the above on my own chart it looks like this:


before padding:
image


after padding:
image

@twopirllc
Copy link
Author

@DanielGoldfarb,

Thanks for the suggested work around.

It's funny that you posted that. Last night I was considering doing something similar, but by adding additional empty Business days to df then passing to plot() like you did.

Also it seems that vlines can only be applied to the main panel. But I'll make a seperate feature request so not to drag Issue 212 further.

I will post a chart update after some refactoring.

Thanks again!
KJ

@DanielGoldfarb
Copy link
Collaborator

@twopirllc yes, there are already two issues requesting the various lines kwargs be available for make_addplot and on any panel.

will do it, but not yet sure how soon; maybe within the next two to three months. in the meantime, generating line data and plotting that data on any panel with make_addplot() is a mildly tedious, but workable, solution.

@twopirllc
Copy link
Author

Hello @DanielGoldfarb,

Sorry it has taken so long to get back to you with an example. I had to create some preliminary code in my project. Anyhow, here is a basic chart with right padding with future dates and the code I used:

class Chart(object):
    # ...

    def _right_pad_df(self, df: pd.DataFrame, rpad: int, delta_unit: str = "D", range_freq: str = "B"):
        if rpad > 0:
            dfpad = df[-rpad:].copy()
            dfpad.iloc[:,:] = np.NaN

            df_frequency = df.index.value_counts().mode()[0] # Most common frequency
            freq_delta = pd.Timedelta(df_frequency, unit=delta_unit)
            new_dr = pd.date_range(start=df.index[-1] + freq_delta, periods=rpad, freq=range_freq)
            dfpad.index = new_dr # Update the padded index with new dates
            df = df.append(dfpad)

        return df

    def _plot(self, df: pd.DataFrame, plot_ratios: tuple = (12, 1.7), **kwargs):
        if df.empty:
            print(f"[X] DataFrame is missing!")
            return
        
        if not isinstance(plot_ratios, tuple):
            print(f"[X] plot_ratios must be a tuple")
            return

        ticker = df.ticker
        
        rpad = kwargs["rpad"] if "rpad" in kwargs else self.rpad
        df = self._right_pad_df(df, rpad)

        df = df.tail(self.last)
        mpf_style = mpf.make_mpf_style(base_mpf_style=mpf_styles[-1], rc={'figure.facecolor': '#EDEDED'})
        width_config={'candle_linewidth':0.8, 'candle_width':0.525, 'volume_width': 0.525}

        mpf.plot(
            df, type="candle", title=ticker,
            style=mpf_style, datetime_format="%-m/%-d/%Y",
            volume=True,
            figsize=(12, 10), scale_padding={'left': 1, 'top': 4, 'right': 1, 'bottom': 1},
            panel_ratios=plot_ratios, xrotation=15,
            update_width_config=width_config, tight_layout=True,
        )

Screen Shot 2020-07-17 at 11 19 33 AM

Thanks again for your time and expertise.
Kevin

@DanielGoldfarb
Copy link
Collaborator

kwarg xlim is now available. pip install --upgrade mplfinance

@DanielGoldfarb DanielGoldfarb added the released code merged into repo AND released to Pypi label Aug 9, 2020
@twopirllc
Copy link
Author

Great! Thank you for your time and excellence.

Regards,
Kevin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request released code merged into repo AND released to Pypi
Projects
None yet
Development

No branches or pull requests

2 participants