mplfinance icon indicating copy to clipboard operation
mplfinance copied to clipboard

Have a problem, when I work with external_axes.

Open lirem opened this issue 4 years ago • 11 comments

Hi, I need to add to the plot some text and I tried to use your guide "How to use your own matplotlib Figure and Axes in mplfinance". But i have an error:

"ValueError: make_addplot() ax kwargs must all be of type matplotlib.axis.Axes"

My code:

import mplfinance as fplt
import pandas as pd

df5M = pd.read_csv("D:\\_users_files\\Kirill\\WORK\\fx2youcom\\df5M.csv", index_col=0, parse_dates=True)


fig = fplt.figure(style='yahoo', figsize=(10.8, 6.4))

ax1 = fig.add_subplot(2, 2, 1)

sma = [fplt.make_addplot(df5M['SMA20'].tail(100), color='#f1afe1'),
       fplt.make_addplot(df5M['SMA50'].tail(100), color='#ffaf6c'),
       fplt.make_addplot(df5M['SMA200'].tail(100), color='#f0dea7')]

fplt.plot(df5M.tail(100),
          type='candle',
          ax=ax1,
          style='yahoo',
          title="long_name",
          ylabel='5 Minutes',
          addplot=sma
          )
fig

Thank you for help, you do really helpful framework!

lirem avatar Jun 06 '21 11:06 lirem

Whenever you pass an external Axes object into mplfinance.plot() using the ax= kwarg, then

  • if you want to plot volume, then you must pass an Axes object in for the volume:
    that is, instead of volume=True do volume=axes where axes is an Axes object on which you want to plot the volume.
  • you must also use kwarg ax= for all calls to mplfinance.make_addplot()

This was noted at the bottom of the subplots page.
I probably should repeat this information also in the external axes notebook.

DanielGoldfarb avatar Jun 06 '21 13:06 DanielGoldfarb

Sorry, but i dont undestand "you must also use kwarg ax= for all calls to mplfinance.make_addplot()", can you insert in my code, what it need?

Please, it's very important for me

lirem avatar Jun 06 '21 13:06 lirem

Each addplot could, in theory, go on a different axes.

Since you are plotting moving averages, I will assume you want them on the same Axes as the candlestick plot, therefore:

sma = [fplt.make_addplot(df5M['SMA20'].tail(100), color='#f1afe1',ax=ax1),
       fplt.make_addplot(df5M['SMA50'].tail(100), color='#ffaf6c',ax=ax1),
       fplt.make_addplot(df5M['SMA200'].tail(100), color='#f0dea7',ax=ax1)]

By the way, for what you are doing (simple candlesticks with some moving averages) you can do the same thing without external axes mode, much easier, by just adding the mav kwarg:

fplt.plot(df5M.tail(100),
          type='candle',
          mav=(20,50),
          style='yahoo',
          title="long_name",
          ylabel='5 Minutes',
          )

In the above example I show only 20 and 50 sma. I left out the 200 moving average because you are only plotting 100 points (df5M.tail(100)). I assume you are using external axes mode in this case where it is not necessary, just as an exercise to learn external axes mode.

DanielGoldfarb avatar Jun 06 '21 15:06 DanielGoldfarb

I need to add external axes because i need to add several inscription to plot.

I assume you are using external axes mode in this case where it is not necessary

I'm agree with you, but my customer want to take data for plotting from file.

Now, when I add ax=ax1 I have a new error:

AttributeError: 'NoneType' object has no attribute 'suptitle'

My code again, if you need:

def create_5m(df5M):
    fig = fplt.figure(style='yahoo', figsize=(10.8, 6.4))
    ax1 = fig.add_subplot(2, 2, 1)
    sma = [fplt.make_addplot(df5M['SMA20'].tail(count_bar), color='#f1afe1', ax=ax1),
           fplt.make_addplot(df5M['SMA50'].tail(count_bar), color='#ffaf6c', ax=ax1),
           fplt.make_addplot(df5M['SMA200'].tail(count_bar), color='#f0dea7', ax=ax1)]
    fplt.plot(df5M.tail(count_bar),
              type='candle',
              style='yahoo',
              title=long_name,
              ylabel='5 Minutes',
              addplot=sma,
              ax=ax1,
              savefig='df5M.png'
              )
    fig

lirem avatar Jun 06 '21 15:06 lirem

This is sort of a bug: The code should actually reject using the title kwarg, and raise an exception telling you that title is invalid when in external axes mode. This is because the title kwarg operates on the Figure, and in external axes mode you have the Figure (not mplfinance).

You have two choices as a workaround:

  1. Set the title on the Axes instead of the Figure. To do this change title=long_name to axtitle=long_name
  2. Set the title on the Figure yourself. After calling fplt.plot() then call: fig.suptitle(long_name)

I also just noticed that you are trying to save the figure with savefig. savefig also does not work in external axes mode.

What you have to do is after calling fplt.plot() then call fig.savefig('df5M.png')


... agree with you, but my customer want to take data for plotting from file.

Again I would strongly suggest that you not use external axes mode. I am not sure what you mean that your customer wants "to take the data fro plotting from file". It is very easy to write an mplfinance script (or gui app) that will read the data for plotting from a file, and that will write the plot itself to a .png or other image file. All this can be done easily without needing external axes mode.

As a general rule, external axes mode is good for a very small number of cases that are not directly support by mplfinance, but, as you are seeing, it has a lot of limitations. Therefore you should only use external axes mode if you cannot accomplish what you want to in another way. So far it seems to me that you can accomplish everything you want to accomplish without needing external axes mode.

DanielGoldfarb avatar Jun 06 '21 19:06 DanielGoldfarb

I have to add a label to the top left and top right corner, below the plot. Can this be done without external axes?

lirem avatar Jun 07 '21 03:06 lirem

Yes, you can instead use kwarg returnfig=True. That will give you access to the axes objects, and you can use them to add text or other annotations to your axes. After calling Axes.test() or Axes.annotate() you will then have to either call mpf.show() to display or fig.savefig() to save the plot to a file.

You may or may not find the above easier than creating your own Figure and Axes, but you can leverage more of the power of mplfinance if you use returnfig=True instead of creating your own Figure and Axes. Your choice. Eventually we will support text and annotations directly in mplfinance, but for now, unfortunately, these are your alternatives.

DanielGoldfarb avatar Jun 07 '21 04:06 DanielGoldfarb

Sorry, but can you show me, for example, how i can can add some text in the upper left corner above the graph. I don't know, how i can do this, sorry.

lirem avatar Jun 07 '21 15:06 lirem

Here is some example code adding text to a Plot.
The data file can be found in the examples/data folder:

#!/usr/bin/env python
# coding: utf-8

# ---------------------
# Text on Plot Example:
# ---------------------

import pandas as pd
import mplfinance as mpf

# Read in the Data:
intraday = pd.read_csv('../data/SP500_NOV2019_IDay.csv',index_col=0,parse_dates=True)
intraday = intraday.drop('Volume',axis=1) # Volume is zero anyway for this intraday data set
intraday = intraday.loc['2019-11-07 09:30':'2019-11-08 16:00',:] # only need part of the data.

# Resample, to every 5 minutes:
rmap = {'Open':'first', 'High':'max', 'Low':'min', 'Close':'last'}
df5m = intraday.resample( '5T').agg(rmap).dropna()

# Use `returnfig=True` to gain access to mplfinance's Figure and Axes objects:
fig, axlist = mpf.plot(df5m,type='candle',mav=(10,30),style='yahoo',figscale=1.5,
                       title='\nPlot Title',ylabel='5 Minute Prices', returnfig=True)

# Add text to the primary Axes.  
# Note regarding the x,y coordinates used for text placement, 
# the x coordinate is the row number in the data frame (0 for far left, len(df5m) for far right),
# and the y-coordinate is the price value on the y-axis:
axlist[0].text(len(df5m)-30, 3095, 'This text is in\nthe Upper Right\ncorner.')
axlist[0].text(          10, 3075, 'This text is in\nthe Lower Left\ncorner.')

# Save the plot to a file.  (Alternatively call `mpf.show()` here to display the plot on the screen).
fig.savefig('df5m.png')

Here is the output, the "df5m.png" file: df5m

DanielGoldfarb avatar Jul 14 '21 22:07 DanielGoldfarb

Here is an annotation example: https://github.com/matplotlib/mplfinance/issues/58#issuecomment-1023612635

DanielGoldfarb avatar Jan 27 '22 21:01 DanielGoldfarb