matplotlib / mplfinance

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

Have a problem, when I work with external_axes. #403

Open lirem opened 3 years ago

lirem commented 3 years ago

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!

DanielGoldfarb commented 3 years ago

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

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

lirem commented 3 years ago

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

DanielGoldfarb commented 3 years ago

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.

lirem commented 3 years ago

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
DanielGoldfarb commented 3 years ago

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.

lirem commented 3 years ago

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

DanielGoldfarb commented 3 years ago

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.

lirem commented 3 years ago

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.

DanielGoldfarb commented 3 years ago

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 commented 2 years ago

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

jprenkou commented 1 month ago

I make two plot by subplot(),How to show data on diffience panel that show in each plot ?