Mplfinance: addplot for signals | ValueError: x and y must be the same size

Created on 14 Jan 2021  路  7Comments  路  Source: matplotlib/mplfinance

I am trying to use addplot to highlight specific candlestick data on the chart. The way I am trying is:

addSignals = mpf.make_addplot(dfTest['close'], type='scatter',marker=mymarker,markersize=45,color=color)
mpf.plot(dfDATE1,type='candle', style='binance',addplot=addSignals)

The error I am getting is: ValueError: x and y must be the same size

[BEFORE SPLITTING DATAFRAMES] I have a column with a reading of 1 if the signal condition is correct, and I isolated those into their own dataframe, dfTest. The one I am trying to use to addplot with scatter signals.

The dataframe for the main `mpf.plot() contains the complete data inside, but obviously minus the signal column since mpf needs OHLC and date index only. I just want to highlight my signal data with a simple marker.

However I am not sure how to do that. If this question is not clear please let me know so I can try and reword it.

question

Most helpful comment

Again, it's very difficult for me to provide an answer without seeing your code and data.

If I could see your code and data, then I could make a specific recommendation regarding your code.
Without it, I can only provide an example that is a guess as to what may be needed in your code:


So I should go back to a copy of the main dataframe without filtering it, but fill any value != to what I want to nan values?

... probably yes, or something like this:

  • Let's say I have a dataframe like this:
print(df)
                   Open         High          Low        Close
Date                                                          
2014-09-11  1992.849976  1997.650024  1985.930054  1997.449951
2014-09-12  1996.739990  1996.739990  1980.260010  1985.540039
2014-09-15  1986.040039  1987.180054  1978.479980  1984.130005
2014-09-16  1981.930054  2002.280029  1979.060059  1998.979980
2014-09-17  1999.300049  2010.739990  1993.290039  2001.569946
2014-09-18  2003.069946  2012.339966  2003.069946  2011.359985
2014-09-19  2012.739990  2019.260010  2006.589966  2010.400024
  • And let's say my "signal" is when the difference between the High and the Low is less than 10.0 ...
ranges = df['High'] - df['Low']
signal = pd.DataFrame(ranges.loc[(ranges < 10.0)],columns=['Signal'])
print(signal)

             Signal
Date                
2014-09-15  8.700074
2014-09-18  9.270020
  • But in order to plot the Signal data with mpf.make_addplot(),
    the length and index of signal needs to match the length and index being passed into mpf.plot().

    • I can do this by first creating a dataframe that is the correct length, with the correct index, but all nan values.

    • then I loop through the signal, and insert the non-nan values into the correctly sized and indexed dataframe:

      ```python

      df_sparse = pd.DataFrame([float('nan')]*len(df),index=df.index,columns=['Signal'])

print(df_sparse)

          Signal

Date
2014-09-11 NaN
2014-09-12 NaN
2014-09-15 NaN
2014-09-16 NaN
2014-09-17 NaN
2014-09-18 NaN
2014-09-19 NaN

for ix,val in zip(signal.index,signal.values):
df_sparse.loc[ix] = val

print(df_sparse)

          Signal

Date
2014-09-11 NaN
2014-09-12 NaN
2014-09-15 8.700074
2014-09-16 NaN
2014-09-17 NaN
2014-09-18 9.270020
2014-09-19 NaN
```

All 7 comments

Not entirely clear, but possibly clear enough. It would be better if I could see the code that generates dfTest['close'].

That said, I'm thinking perhaps your problem is this:
len(dfTest['close']) == len(dfDATE1) must be True.
If not, this won't work.

If you want markers in dfTest['close'] to be sparse, you should fill the non-marker values with float('nan') or numpy.nan.

Please let me know if that helps. Or if you have any other questions. All the best. --Daniel

I applied a function with if statements leading to a yes or no answer on the main dataframe.

Then from there I made a new dataframe from the rows containing the data I am looking for:
dfTest = dfDATE.loc[(dfDATE['type1']=='TYPE 1')]

So at this point I have isolated from the main dataframe, the candles I am looking for, to place a marker on.

--
Reading what you told me here: "If you want markers in dfTest['close'] to be sparse, you should fill the non-marker values with float('nan') or numpy.nan."

So I should go back to a copy of the main dataframe without filtering it, but fill any value != to what I want to nan values?

Thanks for the help so far

Again, it's very difficult for me to provide an answer without seeing your code and data.

If I could see your code and data, then I could make a specific recommendation regarding your code.
Without it, I can only provide an example that is a guess as to what may be needed in your code:


So I should go back to a copy of the main dataframe without filtering it, but fill any value != to what I want to nan values?

... probably yes, or something like this:

  • Let's say I have a dataframe like this:
print(df)
                   Open         High          Low        Close
Date                                                          
2014-09-11  1992.849976  1997.650024  1985.930054  1997.449951
2014-09-12  1996.739990  1996.739990  1980.260010  1985.540039
2014-09-15  1986.040039  1987.180054  1978.479980  1984.130005
2014-09-16  1981.930054  2002.280029  1979.060059  1998.979980
2014-09-17  1999.300049  2010.739990  1993.290039  2001.569946
2014-09-18  2003.069946  2012.339966  2003.069946  2011.359985
2014-09-19  2012.739990  2019.260010  2006.589966  2010.400024
  • And let's say my "signal" is when the difference between the High and the Low is less than 10.0 ...
ranges = df['High'] - df['Low']
signal = pd.DataFrame(ranges.loc[(ranges < 10.0)],columns=['Signal'])
print(signal)

             Signal
Date                
2014-09-15  8.700074
2014-09-18  9.270020
  • But in order to plot the Signal data with mpf.make_addplot(),
    the length and index of signal needs to match the length and index being passed into mpf.plot().

    • I can do this by first creating a dataframe that is the correct length, with the correct index, but all nan values.

    • then I loop through the signal, and insert the non-nan values into the correctly sized and indexed dataframe:

      ```python

      df_sparse = pd.DataFrame([float('nan')]*len(df),index=df.index,columns=['Signal'])

print(df_sparse)

          Signal

Date
2014-09-11 NaN
2014-09-12 NaN
2014-09-15 NaN
2014-09-16 NaN
2014-09-17 NaN
2014-09-18 NaN
2014-09-19 NaN

for ix,val in zip(signal.index,signal.values):
df_sparse.loc[ix] = val

print(df_sparse)

          Signal

Date
2014-09-11 NaN
2014-09-12 NaN
2014-09-15 8.700074
2014-09-16 NaN
2014-09-17 NaN
2014-09-18 9.270020
2014-09-19 NaN
```

Thank you, very informative.

Your code will no doubt help me and others in the future. You put me on the right path today to fix it, and what I done was very hacky but it works...

The code I done: before with the function was:
if condition true: return 'TYPE 1'
else: return 'undefined'

Now, the code is:
if condition true: return data['close']
else: return np.nan

Then apply function: df['type1'] = df.apply(type1,axis=1)

toplot = mpf.make_addplot(df['type1'],scatter=True)
mpf.plot(dfDATE1,type='candle',style='binance',addplot=toplot)

Appreciate it! Why don't you sign up for Brave BAT Rewards? Us and others can tip you from github :)

So my function worked, until I needed to plot the 2 different types of signals.

At which point I come back to your answer:
_"But in order to plot the Signal data with mpf.make_addplot(),
the length and index of signal needs to match the length and index being passed into mpf.plot().
I can do this by first creating a dataframe that is the correct length, with the correct index, but all nan values.
then I loop through the signal, and insert the non-nan values into the correctly sized and indexed dataframe:"_

And the code:

df_sparse = pd.DataFrame([float('nan')]*len(df),index=df.index,columns=['Signal'])

for ix,val in zip(signal.index,signal.values):
   df_sparse.loc[ix] = val

This solved all the problems I've been having.
Thank you so much!

I glad it worked for you. By the way, your approach of

if condition true: return data['close']
else: return np.nan

is actually a very good way to do it. You should be able to apply two different "conditions" to get two different signals that way. But, depending on the existing code, as you found, it may be cleaner to take the other approach (i.e. creating an all nan dataframe and then inserting the signals where needed). Either way is fine.

Thanks for the idea about Brave BAT Rewards. Thankfully, I have a very nice job, and my employer is also a very generous supporter of many open source projects, and software foundations and their conferences. Mplfinance users who want to express their appreciation financially should ideally donate to the Matplotlib fellowship.

(alternatively one can sponsor Matplotlib or make a general donation to NumFocus. Perhaps, if I have time, I'll look into whether it is possible to set up "Brave BAT Rewards" for mplfinance and have the funds sent directly to the Matplotlib fellowship).

All the best. --Daniel

Thank you. I made a second function for the other signal doing the same, adding to a different column. Have it working good now :)

Great man, and I watched your youtube video 'Pandas for Fun and Profit'. Awesome stuff.

Ok cool, thanks for the info, I'll be sure to send over some BAT if that gets setup for all the help. Once again I appreciate your time :+1:

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tessanix picture tessanix  路  5Comments

viorell91 picture viorell91  路  3Comments

ghost355 picture ghost355  路  5Comments

allahyarzadeh picture allahyarzadeh  路  3Comments

Full4me picture Full4me  路  3Comments