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

compatibility with mpld3 #132

Open
esabunor opened this issue May 12, 2020 · 11 comments
Open

compatibility with mpld3 #132

esabunor opened this issue May 12, 2020 · 11 comments
Labels
question Further information is requested

Comments

@esabunor
Copy link

esabunor commented May 12, 2020

hi thank you for this awesome library.
I've been trying to display a candlestick chart, which works well on ipython notebook, but with mpld3, all that displays is this:
Screen Shot 2020-05-12 at 6 55 15 pm

instead of this:
Screen Shot 2020-05-12 at 6 54 48 pm

`df = retrieve_data()
candles = pd.DataFrame( {'Date': pd.to_datetime(df['time']), 'Open': df.Open, 'High': df.High, 'Low': df.Low, 'Close': df.Close, 'Volume': df.Volume})
candles = candles[['Date', 'Open', 'High', 'Low', 'Close', 'Volume']]
candles = candles.set_index(pd.DatetimeIndex(candles["Date"]))

fig, ax = mpf.plot(candles, type='candle', returnfig=True, style='nightclouds')
mpld3.show()`

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

Tega,
I am not familiar with mpld3 and would need some time to look into it (which presently I don't have).

Just took a quick glance though, and can make an uneducated guess: maybe you need to first call mpld3.fig_to_html(fig) and/or maybe just pass the figure in: mpld3.show(fig=fig) ??

Also, as a workaround you may use mplfinance's ability to save the figure to a png or jpg file, and then perhaps mpld3 has a method to display an image file??

Sorry I cannot be more helpful at this time. If you find the solution, please post it here. Otherwise I will probably circle back and take a closer look at this in a couple of weeks.

@balajiperumaal
Copy link

Having the same issue.

image

Any update on this?

@DanielGoldfarb
Copy link
Collaborator

Have any of you actually tried any of the suggestions that I made here?

So for example, maybe something like

fig, ax = mpf.plot(candles, type='candle', returnfig=True, style='nightclouds')
mpld3.fig_to_html(fig)

or similarly, maybe mpld3.save_html(fig) will work, or as suggested above mpld3.show(fig=fig)

Please list here all of things that you have tried.

@balajiperumaal
Copy link

balajiperumaal commented Aug 1, 2021

def index(request):
    df = pd.read_json(os.getcwd()+'/screener/misc/curl.json')
    
    df.columns = ["Date", "Open", "High", "Low", "Close", "Volume"]
    df.index = pd.to_datetime(df["Date"])
    data = pd.DataFrame(df[["Open", "High", "Low", "Close"]])
    fig, ax = mpf.plot(data, type="candle", style="nightclouds", returnfig=True)
    res = mpld3.fig_to_html(fig)
    return HttpResponse(res)

image

df.columns = ["Date", "Open", "High", "Low", "Close", "Volume", "Oi"]
    df.index = pd.to_datetime(df["Date"])
    data = pd.DataFrame(df[["Open", "High", "Low", "Close"]])
    fig = mpf.figure()
    fig, ax = mpf.plot(data, type="candle", style="nightclouds", returnfig=True)
    mpld3.save_html(fig, "test.html")

Same image as above while opening test.html

@DanielGoldfarb
Copy link
Collaborator

DanielGoldfarb commented Aug 3, 2021

I spent some time playing with mpld3 and mplfinance and matplotlib, and I have discovered that the problem is with mpld3, in that it does not handle matplotlib's twinx() and twiny() functionality (and mplfinance uses twinx()).

It appears that mpld3 has classified this issue as an enhancement and has been aware of the issue since 2014.

If I have some time, I will look into alternatives to mplfinance using twinx(). In the meantime, mplfinance external axes mode should work, as long as you avoid calling twinx() or twiny(). (When in external axes mode, mplfinance does not call twinx())

I have tested mpld3 with mplfinance in external axes mode and it worked, however it appears that mpld3 also does a lot of its own formatting of labels, and ticks, etc. This is true even when using plain matplotlib (not mplfinance). This means that whatever mplfinance style you may choose, there is always a possibility that mpld3 will modify that style in whatever ways it chooses.

Keep in mind also that, when in external axes mode, some mplfinance functionality becomes unavailable, and, if desired, must be implemented externally by the caller. One such example is the mplfinance's savefig kwarg. This is not available when in external axes mode, however the caller can call matplotlib's Figure.savefig() function directly on the Figure object.

@balajiperumaal
Copy link

balajiperumaal commented Aug 13, 2021

Hi @DanielGoldfarb,
Thanks for your help!!

I have tried external axes mode. The chart looks good. But the x-axis turned out to be a numbers instead of date.

df = pd.read_json(os.getcwd()+'/screener/misc/curl.json')

    df.columns = ["Date", "Open", "High", "Low", "Close", "Volume", "Oi"]
    df.index = pd.to_datetime(df["Date"])
    data = pd.DataFrame(df[["Open", "High", "Low", "Close"]]) # I've also tried with/without Date column
    fig = mpf.figure(style="charles")
    ax = fig.add_subplot(1, 1, 1)
    ax.grid(False)
    mpf.plot(data, type='candle', ax=ax, volume=False, returnfig=True)
    # mpf.show() <-- This works fine (but opens in separate window)
    res = mpld3.fig_to_html(fig)
    return HttpResponse(res)

Data Sample
image

image
I got that, this issue has to be fixed in mpld3. But as we have look into it already, you can show some light here.

Thanks

@DanielGoldfarb
Copy link
Collaborator

@balajiperumaal Balaji, there are two things that I would suggest you try. First some background:

When plotting dates or datetimes on the x-axis, matplotlib presumes time is continuous. Therefore all datetimes between the minimum x-axis datetime value and the maximum x-axis datetime value are included along the x-axis. In other words, non-trading dates will be part of the plot, and there will be gaps in the plot for weekends and holidays.

Most people prefer not to see these gaps. Therefore the default value for kwarg show_nontrading is False.

But as mentioned above, matplotlib presumes that time is continuous (a somewhat reasonable assumption).

Therefore the way to implement not plotting non-trading days is to make the x-axis not datetimes, but simply the row number in the dataframe. This ensures that there are no gaps in the plot. However, if we want to format the x-axis with datetimes, then we need to map from dataframe row number to the datetime for that row. You can see mplfinance doing this in the code here.

With that background understanding, here are two suggestions to try:

  1. Set show_nontrading=True. You will see gaps for weekends and holidays, but I believe (not sure) mpld3 will recognize the matplotlib dates and format the x-axis accordingly.

  2. If you want to leave show_nontrading=False, then try setting the formatter for the x-axis. I am not sure if mpld3 will respect this, but it's worth a try. (I did noticed, when I was experimenting with matplotlib and mpld3, that mpld3 sometimes likes to do its own formating of axis ticks, ignoring what matplotlib would otherwise do.)
    Here is how you can set the axis formatter similar to what mplfinance normally does:

from mplfinance._utils import IntegerIndexDateTimeFormatter
import matplotlib.dates as mdates

dates     = mdates.date2num(df.index.tz_localize(None).to_pydatetime())
formatter = IntegerIndexDateTimeFormatter(dates,'%b %d')  #  '%b %d' can be any strftime() format you want
ax.xaxis.set_major_formatter(formatter)

I would be interested to know if this works. (Note: '%b %d' can be any strftime() format that you want.)

@balajiperumaal
Copy link

Hi @DanielGoldfarb

I tried using formatter with no luck. When I use show_nontrading=True the chart looks like below (Still numbers instead of date)

image

Thanks for your elaborated answer

@DanielGoldfarb
Copy link
Collaborator

@balajiperumaal
Please show the output from the following:

print(data.index)
print(type(data.index))
print(type(data.index[0]))

I assume your code is still as shown here. If not, please indicate full code. Also, if possible, please post your data input file somewhere that I can access it. If time permits I will look into this during the week.

@balajiperumaal
Copy link

balajiperumaal commented Aug 15, 2021

Hi @DanielGoldfarb
Thanks again for the quick response.

here is the screenshot of the required variables.

image

The result of this code,
image

Sample Input File

I've also tried to remove tz_localize(None) as it is already a timezone. But still it didn't work.

Thanks

@haziq-zur
Copy link

Hi @balajiperumaal , previously I also encounter this kind of issue but with plotly graphing packages. In my case, I had to reorganize the data back into time format after the indexing is completed. Maybe you can also try this fix.

df.reset_index(inplace=True)
df['Date'] = df['Date'].map(mdates.date2num)
df['Date'] = df['Date'].map(mdates.num2date)

On a side note, I have my columns in the right order but there is still a problem. The date doesn’t have the right format and since it is the index, I cannot manipulate it. Therefore, I reset the index and then convert the datetime to a number by using:

df.reset_index(inplace=True)
df['Date'] = df['Date'].map(mdates.date2num)

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

No branches or pull requests

4 participants