Skip to content

Flashing (blinking) Axes labels during animation #296

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

Closed
ttt710516 opened this issue Dec 19, 2020 · 9 comments
Closed

Flashing (blinking) Axes labels during animation #296

ttt710516 opened this issue Dec 19, 2020 · 9 comments
Labels
bug Something isn't working released code merged into repo AND released to Pypi

Comments

@ttt710516
Copy link

Hi,
I tried the following example code.
https://github.com/matplotlib/mplfinance/blob/master/examples/mpf_animation_demo1.py
It seems having performance issues. When the figure is updated, the screen is flashing.
Do you have any idea to improve it?

Sincerely,
Kang

@ttt710516 ttt710516 added the question Further information is requested label Dec 19, 2020
@DanielGoldfarb
Copy link
Collaborator

This sounds familiar. This was reported by only one other person sometime back in August, and I was unable to reproduce the issue on my system. I am trying to find my notes on the matter. At one point I think I was able temporarily to reproduce it, and (if I recall correctly) it only happened with a specific matplotlib backend. Also, as I also recall, not plotting volume made the problem go away.

I will continue to look for my notes on the problem. I believe I had a fix for it, but I can't recall if I actually implemented or published the fix. As I mentioned, it was only reprted once before and was difficult to reproduce.

In the meantime, can you please indicate what version of matplotlib and mplfinance you are running, and which backend:

import matplotlib
print(matplotlib.__version__)
print(matplotlib.get_backend())

import mplfinance as mpf
print(mpf.__version__)

Please also try the following:
After running mpf_animation_demo1.py and verifying that you still see the flashing, then please modify line 32 of that file and remove volume=ax2, so that the line now reads:

mpf.plot(data,ax=ax1,type='candle')

and then rerun it, and let me know if the flashing goes away.

Thank you. --Daniel

@ttt710516
Copy link
Author

ttt710516 commented Dec 20, 2020

Hi,
My original version of matplotlib is 3.1.1, and the flashing is in ax2 only.
I upgraded my matplotlib to 3.3.3. all seem to be fine.
Anyway, the result with new matplotlib is as the follows.
3.3.3
Qt5Agg
0.12.7a0
I don't know why the backend isQt5Agg?

However, I still got the same problem when integrating with tkinter. my code is as the follows. The ticklabels of ax2 is still flashing.

------code--------------

import pandas as pd
import mplfinance as mpf
import matplotlib.animation as animation
import tkinter
from matplotlib.backends.backend_tkagg import (
    FigureCanvasTkAgg, NavigationToolbar2Tk)
import matplotlib
print(matplotlib.__version__)
print(matplotlib.get_backend())

import mplfinance as mpf
print(mpf.__version__)

idf = pd.read_csv('abc.csv',index_col=0,parse_dates=True)
idf.shape
idf.head(3)
idf.tail(3)
df = idf.loc['2011-07-01':'2011-12-30',:]

fig = mpf.figure(style='yahoo', figsize=(7, 8))
ax1 = fig.add_subplot(2,1,1)
ax2 = fig.add_subplot(3,1,3)

def animate(ival):
    if (20+ival) > len(df):
        print('no more data to plot')
        ani.event_source.interval *= 3
        if ani.event_source.interval > 12000:
            exit()
        return
    data = df.iloc[0:(20+ival)]
    ax1.clear()
    ax2.clear()
    mpf.plot(data,ax=ax1,volume=ax2,type='candle')

root = tkinter.Tk()
canvas = FigureCanvasTkAgg(fig, master=root)  # A tk.DrawingArea.
canvas.draw()
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)
ani = animation.FuncAnimation(fig, animate, interval=250)
mpf.plot(df.iloc[0:20],ax=ax1,volume=ax2,type='candle')

root.mainloop()

Sincerely,
Kang

@DanielGoldfarb
Copy link
Collaborator

Kang,
I will try to reproduce on my end.
Can you please verify whether you still see the flashing with tkinter, if you remove the volume=ax2 kwarg?
Thanks.
--Daniel

@DanielGoldfarb
Copy link
Collaborator

DanielGoldfarb commented Dec 20, 2020

I am able to reproduce. Looking into this.

@DanielGoldfarb DanielGoldfarb added bug Something isn't working and removed question Further information is requested labels Dec 20, 2020
@DanielGoldfarb
Copy link
Collaborator

DanielGoldfarb commented Dec 20, 2020

Here is the explanation of the bug, for anyone who is interested. (And for myself, for the record, so that I can remember what was going on). The bug has nothing to do with performance. But rather has to do with some special formatting mplfinance does specifically for Volume data. Since volume data typically may be a large order of magnitude, matplotlib will default to displaying scientific notation. When matplotlib does this, by default it looks something like this:

Figure_0

Notice the "1e8" just above the volume panel on the left side.


Mplfinance wants it to be clear that the exponent applies specifically to the volume, so by default Mplfinance moves the exponent to be part of the Volume axis label, like this:

Figure_1

Mplfinance does this by first calling .draw() to allow matplotlib to do the work of deciding when and how to format the axis with scientific notation. It then grabs the exponent display (see .get_offset() in the code below), and erases the exponent from its original location (.offsetText.set_visible(False)) and adds it to the volume axis label (vol_label = 'Volume'+offset).
The code to do this is shown below:

    if config['volume']:
        volumeAxes.figure.canvas.draw()  # This is needed to calculate offset
        offset = volumeAxes.yaxis.get_major_formatter().get_offset()
        volumeAxes.yaxis.offsetText.set_visible(False)
        if len(offset) > 0:
            offset = (' x '+offset)
        if config['ylabel_lower'] is None:
            vol_label = 'Volume'+offset
        else:
            if len(offset) > 0:
                offset = '\n'+offset
            vol_label = config['ylabel_lower'] + offset
        volumeAxes.set_ylabel(vol_label)

For most matplotlib backends this is fine. The original volumeAxes.figure.canvas.draw() does not actually get displayed. Later, when mplfinance (or the user) calls plt.show(), then .draw() gets called again, with the scientific notation reformatted to be part of the volume axis label, and it is this later .draw() that actually gets displayed. The problem is, it appears that when tkinter is in use, then both calls to .draw() get displayed - thus the "flashing" on the screen as the label first gets drawn one way, and immediately afterwards gets drawn another way.

The same thing is happening with regard to the x-axis labels (when in external axis mode), because the x-axis labels get formatted after the first draw. However the x-axis label issue is easily fixed by moving that x-axis formatting to before the first .draw(). But the y-axis scientific notation formating cannot be moved to before the first call to .draw(), because it is that .draw() specifically that does the scientific notation formatting in the first place!

The advantage to this approach is that we allow matplotlib to do all the work and decision making for the scientific notation. The disadvantage is an extra call to .draw(). At the time that I originally wrote this code, it seemed worth it, as the extra call to .draw() is a very slight performance hit, and it seemed there were no other side effects to the extra .draw(). However now it is apparent that, at least when tkinter is in use, there is also a visual display issue.

The solution will be for Mplfinance to do its own scientific notation formatting (outside of matplotlib), so that we can avoid the extra call to .draw(). This will all remain transparent to the user. I hope to work on this fix tomorrow.

@DanielGoldfarb DanielGoldfarb changed the title Performance for animation Flashing (blinking) Axes labels during animation Dec 20, 2020
@ttt710516
Copy link
Author

Hi, DanielGoldfarb
Thanks for the update. I will try the new version when releasing.
Ohter questions here.

  1. Do you have any idea about why the backend is Qt5Agg?
  2. forgot to mention that, ax title is flashing as well.

Sincerely,
Kang

@DanielGoldfarb
Copy link
Collaborator

DanielGoldfarb commented Dec 21, 2020

Kang,

  1. Do you have any idea about why the backend is Qt5Agg?

Matplotlib has a prioritized list of backends that it tries to use, and will (by default) use the first one from the list that it finds installed on your system. The graphics library or libraries ("backends" from matplotlib's point of view) that are installed on your system depend on two things: (1) what graphics libraries come with your operating system, and (2) what additional graphics libraries you may have installed yourself. For example, I am running "Ubuntu 20.04.1 LTS" under Window Subsystem for Linux (WSL2), and I have not installed any graphics libraries other than what came with WSL Ubuntu 20, and my matplotlib backend is also defaulting to "Qt5Agg." For more information see this question and answer here.

  1. forgot to mention that, ax title is flashing as well.

Understood. This is part of the same issue and should go away with the fix that I am implementing.

DanielGoldfarb added a commit that referenced this issue Dec 22, 2020
New handling of volume exponent; and assorted scratch_pad additions:

This PR is primarily to implement a new way to handle the volume exponent; the new way avoids calling `.draw()` which in turn eliminates the bug mentioned in issue #296, and also mentioned/described in a previous email from S.G. ([commit 2c88663](2c88663))

This PR also includes a lot of scratch_pad work for investigations of various issues (#282, #236, #241), and for an mplfinance presentation: including comparison of old and new api's, intraday animation with volumes, generation of animation gifs, etc.
@DanielGoldfarb DanielGoldfarb added merged / awaiting release to pypi code merged into repo, but not yet released to Pypi released code merged into repo AND released to Pypi and removed merged / awaiting release to pypi code merged into repo, but not yet released to Pypi labels Dec 22, 2020
@DanielGoldfarb
Copy link
Collaborator

Kang,

Please test and let me know if this is working now. To install the fix:

pip install --upgrade mplfinance

@ttt710516
Copy link
Author

It works well now.
Thanks for your effort.

Sincerely,
Kang

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working released code merged into repo AND released to Pypi
Projects
None yet
Development

No branches or pull requests

2 participants