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

How to write names in hlines(Horizontal lines) #123

Open
Ripper1111 opened this issue May 4, 2020 · 11 comments
Open

How to write names in hlines(Horizontal lines) #123

Ripper1111 opened this issue May 4, 2020 · 11 comments
Labels
enhancement New feature or request question Further information is requested

Comments

@Ripper1111
Copy link

mpl.plot(frame,hlines=dict(hlines=[support1,support2,resistance1,resistance2],colors=['g','g','r','r'],linestyle='-.'),type='candlestick', style = s,title='Pivot Chart',ylabel='Price',returnfig=True)
I want to give name in front of these horizontal lines. How to do that?

@Ripper1111 Ripper1111 added the question Further information is requested label May 4, 2020
@DanielGoldfarb
Copy link
Collaborator

Do you mean a text annotation on the plot, describing each horizontal line?

@Ripper1111
Copy link
Author

Do you mean a text annotation on the plot, describing each horizontal line?

Yes

@DanielGoldfarb
Copy link
Collaborator

DanielGoldfarb commented May 5, 2020

Direct and full support for text annotations is not yet available; probably will be within the next month or two.

In the meantime, there is a workaround, to set returnfig=True when calling mpf.plot(). This will cause 'mpf.plot() to return the Figure and Axes (and not call plt.show()) which will allow you to call text() on the axes of your choice (and the call plt.show()).

For more details, see these two comments here:

  1. how to add text to figure #60 (comment)
  2. how to add text to figure #60 (comment)

@mjessa12
Copy link

mjessa12 commented Dec 2, 2020

Hello @DanielGoldfarb ,

Has there been any progress to be able to add text annotations to mplfinance based on your response above?

Thanks!

@krazykoder
Copy link

Hello @DanielGoldfarb just checking in to see if you got a chance to add the text annotations functionality to mplfinance.
Appreciate your help.

thanks!

@DanielGoldfarb
Copy link
Collaborator

@krazykoder

Not yet. I realize it has been a while. Working on some other major enhancemnts, one in particular taking a long time (to be able to extrapolate x-axis, and have more control over placement of ticks on the x-axis). Have you been able to make any of the above mentioned workarounds work for you? Let me know if you need any assistance.

All the best. --Daniel

@DanielGoldfarb DanielGoldfarb added the enhancement New feature or request label Apr 30, 2021
@DanielGoldfarb
Copy link
Collaborator

See also #387 (comment)

@krazykoder
Copy link

krazykoder commented May 7, 2021

Daniel, I was able to follow the instructions in your post on the row number and use this to my purpose. Sharing a snippet of my code here.

#Text annotate example 
ax1 = axlist[0]
style = dict(size=5, color='black')
xpos = df[s:e].index.get_loc('2021-03-19 10:30', method='nearest') # find row # with the nearest index to x
axlist[0].text(xpos, 40, "| 03/19", **style)
fig.show()

Would appreciate it if you have a better idea. In this case, I am annotating on a larger time frame with data from a smaller timeframe. Ideally, I would want to place the marker and text somewhere in between the two-row of a larger timeframe - which is not technically possible in this approach. So I am finding the nearest date and row number and annotating the text here.

@DanielGoldfarb
Copy link
Collaborator

DanielGoldfarb commented May 7, 2021

@krazykoder
Thanks for posting your snippet of code. I didn't know about the method kwarg to Index.get_loc().

The basic idea, when the date you want is between two of the dates in the index, is to linearly interpolate between them. The trick is that, to interpolate, you must first convert the dates to matplotlib dates (which are actually floats and thus permit basic math).

Here's a piece of code from the enhancement that I am working on. I hope to release this into mplfinance sometime this summer. In the meantime you can copy/paste the code below.

When I wrote the code below, I used slices on a series (taking the first or last item from the slice) in order to find the previous and next loc for a given date. Now that I know about the method kwarg, it seems to me it can also work using .get_loc method=ffill and method=bfill but I have not tested it that way. It works fine as written below:

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

import pandas     as pd
import datetime   as datetime
import matplotlib.dates as mdates

def date_to_mdate(date):
    """Convert a `date` to a matplotlib date:

    Input: `date` may be any of:
        (1) parseble string containing a date or datetime as a string,
        (2) python `datetime.date` or `datetime.datetime`,object
        (3) pandas.Timestamp object

    Returns a Matplotlib Date: floating point number of days from 01-Jan-0001, plus one day.
    """
    if isinstance(date,str):
        pydt = pd.to_datetime(date).to_pydatetime()
    elif isinstance(date,pd.Timestamp):
        pydt = date.to_pydatetime()
    elif isinstance(date,(datetime.datetime,datetime.date)):
        pydt = date
    else:
        return None
    return mdates.date2num(pydt)

def date_to_loc(dtindex,date):
    if not isinstance(dtindex,pd.DatetimeIndex):
        raise TypeError('dtindex must be a `pandas.DatetimeIndex` object')
    dtseries = dtindex.to_series()
    d1s = dtseries.loc[date:]
    if len(d1s) < 1:
        sdtrange = str(dtseries[0])+' to '+str(dtseries[-1])
        raise ValueError('Specified date "'+str(date)+'" is beyond '+
                         '(greater than) range of datetime index ('+sdtrange+').')
    d1 = d1s.index[0]
    d2s = dtseries.loc[:date]
    if len(d2s) < 1:
        sdtrange = str(dtseries[0])+' to '+str(dtseries[-1])
        raise ValueError('Specified date "'+str(date)+'" is before '+
                         '(less than) range of datetime index ('+sdtrange+').')
    d2 = d2s.index[-1]
    # If there are duplicate dates in the series, for example in a renko plot
    # then .get_loc(date) will return a slice containing all the dups, so:
    loc1 = dtseries.index.get_loc(d1)
    if isinstance(loc1,slice): loc1 = loc1.start
    loc2 = dtseries.index.get_loc(d2)
    if isinstance(loc2,slice): loc2 = loc2.stop - 1

    if loc1 == loc2:
        return float(loc1)

    # convert dates to matplotlib dates which are
    # floats and thus permit basic math (+-*/) in
    # order to be able to linearly interpolate:
    mpd1 = date_to_mdate(d1)
    mpd2 = date_to_mdate(d2)
    mpd  = date_to_mdate(date)

    slope   = (loc2 - loc1) / (mpd2 - mpd1)
    yitrcpt = loc1 - (slope*mpd1)

    x = (slope)*mpd + yitrcpt
    return x

# Test the code:

# Generate a datetime index with a point every 15 minutes:
ix = pd.date_range('5/7/2021 09:30','5/7/2021 16:00',freq='15T')

print('datetime index=')
print(ix,'\n')

# Check some dates that fall on and around one of the datetime index points:
checkdates = ['2021-05-07 11:43','2021-05-07 11:44','2021-05-07 11:45',
              '2021-05-07 11:46','2021-05-07 11:55','2021-05-07 11:50']
for date in checkdates:
    loc = date_to_loc(ix,date)
    print('date=',date, ' loc=',loc,)

Output from the above test:

datetime index=
DatetimeIndex(['2021-05-07 09:30:00', '2021-05-07 09:45:00',
               '2021-05-07 10:00:00', '2021-05-07 10:15:00',
               '2021-05-07 10:30:00', '2021-05-07 10:45:00',
               '2021-05-07 11:00:00', '2021-05-07 11:15:00',
               '2021-05-07 11:30:00', '2021-05-07 11:45:00',
               '2021-05-07 12:00:00', '2021-05-07 12:15:00',
               '2021-05-07 12:30:00', '2021-05-07 12:45:00',
               '2021-05-07 13:00:00', '2021-05-07 13:15:00',
               '2021-05-07 13:30:00', '2021-05-07 13:45:00',
               '2021-05-07 14:00:00', '2021-05-07 14:15:00',
               '2021-05-07 14:30:00', '2021-05-07 14:45:00',
               '2021-05-07 15:00:00', '2021-05-07 15:15:00',
               '2021-05-07 15:30:00', '2021-05-07 15:45:00',
               '2021-05-07 16:00:00'],
              dtype='datetime64[ns]', freq='15T')

date= 2021-05-07 11:43  loc= 8.866666666930541
date= 2021-05-07 11:44  loc= 8.933333333581686
date= 2021-05-07 11:45  loc= 9.0
date= 2021-05-07 11:46  loc= 9.066666666883975
date= 2021-05-07 11:55  loc= 9.666666666744277
date= 2021-05-07 11:50  loc= 9.333333333255723

@DanielGoldfarb
Copy link
Collaborator

Btw, just realized that loc2 - loc1 is always 1.0 so these three lines:

    slope   = (loc2 - loc1) / (mpd2 - mpd1)
    yitrcpt = loc1 - (slope*mpd1)
    x = (slope)*mpd + yitrcpt

can be replaced with one line:

    x = loc1 + ((mpd-mpd1)/(mpd2-mpd1))

@akarun2405
Copy link

Good to know that annotate feature is something on the roadmap Daniel.. Looking forward to it. Do you know when you expect the feature to drop?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request question Further information is requested
Projects
None yet
Development

No branches or pull requests

5 participants