Skip to content

Hiding figure popup window when using Tkinter #304

Closed

Description

@KohliBuilt

First off, I love mplfinance and thanks for all your work!

I just started putting together a GUI to help me quickly review financial charts. I keep getting the figure window in addition to the plot being embedded in the GUI, as you can see below. Is there anyway to prevent the Figure 1 window from being presented?

image

Parts of my code:

from tkinter import Tk,Label,Menu,filedialog,Button,Frame
import pandas as pd
import KohliFunctions as kb
import json
import mplfinance as mpf
from matplotlib.figure import Figure

import matplotlib as matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

def getCandlestickChart():
    chartData = DataSet.historicalData
    symbol = DataSet.symbol
    mc = mpf.make_marketcolors(up='#7DFFB8', #Light Green
                               down='#FF7979', #Light Red
                               edge='black',
                               wick='black',
                               volume='in')
    
    s  = mpf.make_mpf_style(base_mpl_style="seaborn", 
                            mavcolors=["lightseagreen","orange"],
                            facecolor = "#F9FBFD",
                            gridcolor = "#F2F2F2",
                            gridstyle = "--",
                            marketcolors=mc)
    
    fig, ax = mpf.plot(chartData,type='candle',
                      style = s,
                      tight_layout=True,
                      volume=True,   
                      title = f"2 Month Rolling - {symbol}",
                      figratio=(12,6),
                      returnfig=True
                      )
    
    
    canvas = FigureCanvasTkAgg(fig, master=middleFrame)   
    canvas.draw()
    canvas.get_tk_widget().grid(row=0, column=0)


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
window = Tk()
window.geometry('1200x900') #Window Size

topFrame = Frame(window, width=1180, height= 175, bg='white')
topFrame.grid(row=0, column=0, padx=10, pady=5)
topFrame.grid_propagate(False)

middleFrame = Frame(window, width=1100, height= 400, bg='white')
middleFrame.grid(row=1, column=0, padx=10, pady=5)

bottomFrame = Frame(window, width=1100, height= 200)
bottomFrame.grid(row=2, column=0, padx=10, pady=5)

window.mainloop()

Activity

  1. DanielGoldfarb commented on Dec 27, 2020

    @DanielGoldfarb
    Collaborator

    I am not very familiar with using tkinter. In theory, because you have specified returnfig=True, then mpf.plot() will not call .show() and so I would expect that "the Figure 1 window" would not appear.

    Perhaps someone with more experience using matplotlib with tkinter (for example @tacaswell or someone else within the @matplotlib/community) will have some insights into what is causing the Figure 1 window to be drawn.

    For me to try to determine what's going on, I would need to see all of your code. For example, where does getCandlestickChart() get called?

  2. DanielGoldfarb commented on Dec 27, 2020

    @DanielGoldfarb
    Collaborator

    Just to clarify "to see all of your code" ... I don't really need all of it, but I do need a complete set of code to minimally reproduce the issue if you would like me to look into it.

  3. KohliBuilt commented on Dec 28, 2020

    @KohliBuilt
    Author

    Thanks for your quick reply!

    I put together a sample code that you should be able to just copy, paste and run.

    I also noticed that with tight_layout=True & figscale=0.50 some of the plot is cutoff. Is this normal?
    image

    Sample Code:

    import mplfinance as mpf
    import pandas as pd
    import matplotlib as matplotlib
    matplotlib.use("TkAgg")
    
    from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
    from tkinter import Tk,Button,Frame
    
    def getCandlestickChart():
        mc = mpf.make_marketcolors(up='#7DFFB8', #Light Green
                                   down='#FF7979', #Light Red
                                   edge='black',
                                   wick='black',
                                   volume='in')
        
        s  = mpf.make_mpf_style(base_mpl_style="seaborn", 
                                mavcolors=["lightseagreen","orange"],
                                facecolor = "#F9FBFD",
                                gridcolor = "#F2F2F2",
                                gridstyle = "--",
                                marketcolors=mc)
        
        fig, ax = mpf.plot(chartData,type='candle',
                          style = s,
                          tight_layout=True, 
                          title = "Test Plot",
                          figratio=(12,6),
                          figscale=0.50,
                          returnfig=True
                          )
        
        
        canvas = FigureCanvasTkAgg(fig, master=graphFrame)   
        canvas.draw()
        canvas.get_tk_widget().grid(row=0, column=0)
    
    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    #Generate a dataset, "chartData"
    d = {'date': ["2020-04-16","2020-04-17","2020-04-20"],
         'open': [18.03, 18.53,18.57],
         'high': [18.73,18.53,18.57],
         'low': [16.73,17.5,17.257],
         'close': [16.94,18.36,17.71],
         }
    df = pd.DataFrame(data=d)
    chartData = df.sort_values(by='date')
    chartData['date'] = pd.to_datetime(chartData['date'],format='%Y-%m-%d')
    chartData = chartData.set_index('date')
    
    #Setup Tkinter and frames ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    window = Tk()
    window.title("Plot Test") #Window Title
    window.geometry('600x390') #Window Size
    #Graph frame
    graphFrame = Frame(window, width=600, height= 300, bg='white')
    graphFrame.grid(row=0, column=0, padx=10, pady=5)
    #Button Frame
    bottomFrame = Frame(window, width=600, height= 75)
    bottomFrame.grid(row=2, column=0, padx=10, pady=5)
    
    #Add Button ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    btn = Button(bottomFrame, text="Plot!", command=getCandlestickChart)
    btn.grid(column=0, row=0)
    
    #Tkinter Main Loop
    window.mainloop()
  4. DanielGoldfarb commented on Dec 28, 2020

    @DanielGoldfarb
    Collaborator

    Thanks. I am able to run it, but when I click plot I get just the one plot (not the extra "Figure 1" window).

    Perhaps later tonight when I have a little more time I will try running it on some of my other systems. This worked fine (no extra window) on WSL2 Ubuntu. I also have a separate Ubuntu boot (not under WSL), a Mac, and a Red Hat that I can try. Btw, what is your environment?

    Regarding the tight_layout and the figscale apparently not interacting well (and thereby cutting off some of the plot), I haven't seen this but I am not surprised. Mplfinance cannot do a standard Matplotlib tight_layout (something to do with Matplotlib thinking the Axes are incompatible with tight_layout).

    Therefore Mplfinance implements its own tight_layout by adjusting the padding around the Figure. It is understandable that the algorithm may not adapt well to scaling down the size of the Figure. Perhaps some day that algorithm can be improved. In the meantime, I was able to fix it by increasing the padding at the bottom using kwarg scale_padding=dict(bottom=1.75) in your code:

    fig, ax = mpf.plot(chartData,type='candle',
                          style = s,
                          tight_layout=True, 
                          title = "Test Plot",
                          figratio=(12,6),
                          figscale=0.50,
                          scale_padding=dict(bottom=1.75),
                          returnfig=True
                          )

    You can read more about scale_padding in this comment here.

    HTH

  5. KohliBuilt commented on Dec 28, 2020

    @KohliBuilt
    Author

    Thanks so much for the feedback on the scaling issue!

    I had a weird feeling that this might be a system or user setting error. Guess we haven’t fully confirmed this. I am running Windows 10 with Spyder IDE. I did reset all preferences back to default and I still get the second figure window.

  6. DanielGoldfarb commented on Dec 28, 2020

    @DanielGoldfarb
    Collaborator

    I installed python on Windows 10. I took the above test script, write it to disk using notepad, and then from powershell I ran python on that script (I did not install Spyder). I got the same result as when I ran it on Ubuntu: no second window. Everything seems normal. Will have to try to involve someone who is more expert than I am with matplotlib backends and GUIs who may have a clue here. Obviously something environmental, but I have no idea where to even begin.

    @KohliBuilt perhaps try that: Save the test script to a file and run it under PowerShell or CommandPrompt. Then depending on whether you still see the issue you will know whether it's a windows envinroment thing, or a Spyder environment thing.

  7. DanielGoldfarb commented on Dec 28, 2020

    @DanielGoldfarb
    Collaborator

    OK. I installed Spyder and ran it from inside Spyder and indeed I am able to reproduce the problem. This is clearly something specific to Spyder. We had another issue a while back that was also specific to Spyder and while it is unlikely this is related to that, it may be worth noting that Spyder runs Ipython in pylab mode which may treat things differently. For example, in that case it was found that None was treated as False in pylab mode but as True in all other environments (or perhaps "treated as" is the wrong expression; perhaps there was a different "default" boolean value that was used when the variable in question was of NoneType).

    At any rate, this is clearly Spyder related. The question is now whether we can isolate the cause and possibly patch mplfinance so that it will behave the same in Spyder as in other environments.

  8. DanielGoldfarb commented on Dec 28, 2020

    @DanielGoldfarb
    Collaborator

    Adding the following to your script fixes the issue in Spyder:

    import matplotlib.pyplot as plt
    plt.ioff()

    reference: https://stackoverflow.com/a/53217287/1639359

  9. KohliBuilt commented on Dec 28, 2020

    @KohliBuilt
    Author

    It worked!!! @DanielGoldfarb you are amazing and I greatly appreciate all your time and support!!

  10. DanielGoldfarb commented on Dec 28, 2020

    @DanielGoldfarb
    Collaborator

    Glad it worked!

  11. KohliBuilt commented on Dec 29, 2020

    @KohliBuilt
    Author

    @DanielGoldfarb I don't think the solution presented has fully resolved our issue. I noticed that when I close the GUI window the script continues running...which leads me to believe there is still some open window or figure that is hidden. For some reason it is not being destroyed when I close the main GUI window.

    Maybe there is a way to close it?

    For now I am running plt.close(fig) after the mpf.plot function. However, you still see the figure window quickly pop up then get closed.

        fig, ax = mpf.plot(chartData,type='candle',
                          style = s,
                          tight_layout=True, 
                          title = "Test Plot",
                          figratio=(12,6),
                          figscale=0.50,
                          returnfig=True
                          )
        plt.close(fig)
  12. DanielGoldfarb commented on Dec 30, 2020

    @DanielGoldfarb
    Collaborator

    I'm really not sure what I am doing with Spyder and tkinter, since I haven't really used them before; but with a little googling and some reasoning I was able to get it working. First let me describe what I am doing and what I saw.

    I am running your test program as a .py file on the left side of the Spyder interface. When I click the green triangle ("Run File") the window pops up with a button that says "Plot!". At the same time, in the IPython console I see

    In [1] runfile('C:/Users/dgold/issue304.py', wdir='C:/Users/dgold')

    I then click the "Plot!" button and the candlestick plot appears in the window. If I then click the "X" in the upper right hand corner, the window closes, but I do NOT see In [2]: in the IPython console as I would expect. After that, I am also unable to run the file again until I click on the "Consoles" menu and choose "Restart kernel".

    The main reason for the above description is just to make sure we are running things more-or-less the same way.


    I don't know how you got it working at all with plt.close() because, for me, that messes things up and I never see the candlestick plot. However I was able to get it working as follows:

    • I wrote a function called on_closing:
    def on_closing():
        plt.close('all')
        window.destroy()
    • Then, just before calling window.mainloop() I added the following:
    window.protocol("WM_DELETE_WINDOW",on_closing)
    

    That seems to have done the trick. Let me know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions