Search code examples
pythonfileuser-interfacetkinterfolderbrowserdialog

file browser and root opening at end of script


i have a programme that takes user input for folder save location and a file selection to take data from

i have used tkinter's filedialog.askdirectory() and askopenfilename() to do these tasks as shown below:

import pandas as pd
from tkinter import Tk
from tkinter import filedialog
from tkinter.filedialog import askopenfilename
from tkinter import *

############################################################### Reading Excel ###############################################################

print("\nSelect save folder:\n")
root = Tk()
root.withdraw()
savefilepath = filedialog.askdirectory()

print("\nSelect Rainfall .xlsx file:\n")
root2 = Tk()
root2.withdraw()
rainfallpath = askopenfilename()

rainfall = pd.read_excel(rainfallpath, sheet_name='Rainfall', usecols='B:D')
amounts = rainfall["Amount (mm)"]

range_pd = pd.read_excel(rainfallpath, sheet_name='Rainfall Statistics', usecols='K')

at the end of the script, however, the file browser and the root open unexpectedly as shown:

end result

the final lines of my code export the results to the folder location:

with pd.ExcelWriter(savefilepath + "/Harvesting_Output.xlsx") as writer:
    harvesting.to_excel(writer, sheet_name = "Harvesting")
    harvesting_stats.to_excel(writer, sheet_name="Harvesting Statistics")

plt.show()

the programme works perfectly up until plt.show() so i suspect this is causing the problem but im not sure why.

EDIT: After playing around with the position of the plt.show() I have found that this is definitely the issue, but am still unsure as to why it is causing the root and file browser to open?

The following code will produce the issue using the data set i have linked after it:

import pandas as pd
import matplotlib.pyplot as plt
from tkinter import Tk
from tkinter import filedialog
from tkinter.filedialog import askopenfilename
from tkinter import *

print("\nSelect save folder:\n")

root = Tk()
root.withdraw()
savefilepath = filedialog.askdirectory()

print("\nSelect Rainfall .xlsx file:\n")

rainfallpath = askopenfilename()

rainfall = pd.read_excel(rainfallpath, sheet_name='Rainfall', usecols='B:D')
amounts = rainfall["Amount (mm)"]

range_pd = pd.read_excel(rainfallpath, sheet_name='Rainfall Statistics', usecols='K')
range_end = range_pd.iat[0,0]

amounts.iloc[0:50].plot.line(y="Amount (mm)", x='Day', color='blue', legend=True)
plt.show()

https://www.dropbox.com/scl/fo/89y3vo465b38g3eewkmm7/h?dl=0&rlkey=imn0uin56gv81oo36in023y5g

why is this happening?


Solution

  • I also can't reproduce your problem on Windows 10 but on Mac OS 10.14.6 with Python 3.10 I've got the same result.

    It seems to be a problem with matplotlib and I found a possible solution by updating root before asking for the file.

    root.update()
    rainfallpath = askopenfilename()
    

    This way the dialog would close, but I found no way to hide the tkinter window that pops up after plt.show()

    So what finaly worked was running mathplot in interactive mode and then run the mainloop. After 1ms the root window gets hidden.

    This probably could be optimized, but it seems to work.

    The reason why i put root as parent of the dialogs is just a visual one. This way you kinda hide the root window behind the dialog, as you can't withdraw earlier or it wont work. (at least in my tests it didn't)

    import pandas as pd
    import matplotlib.pyplot as plt
    from tkinter.filedialog import askopenfilename, askdirectory
    import tkinter as tk
    
    root = tk.Tk()
    root.title('rainfall')
    print("\nSelect save folder:\n")
    
    savefilepath = askdirectory(parent=root)
    
    print("\nSelect Rainfall .xlsx file:\n")
    
    rainfallpath = askopenfilename(parent=root)
    
    rainfall = pd.read_excel(rainfallpath, sheet_name='Rainfall', usecols='B:D')
    amounts = rainfall["Amount (mm)"]
    
    range_pd = pd.read_excel(rainfallpath, sheet_name='Rainfall Statistics', usecols='K')
    range_end = range_pd.iat[0, 0]
    
    amounts.iloc[0:50].plot.line(y="Amount (mm)", x='Day', color='blue', legend=True)
    
    plt.ion()
    plt.show()
    root.after(1, root.withdraw)
    root.mainloop()