Andrew Hicks
Andrew Hicks

Reputation: 662

Need help adjusting a multi-bound tkinter combobox python script to a nested dictionary source

I am working on a three-level bounded tkinter combobox and I am trying to alter my script to source from a nested dictionary rather then a dictionary and a nested list. My question is a follow-up to this one.

Below is the script that I am using to structure the geography source of the combobox.

def GeoLoad():
    global State
    State = {
        "Alabama":['Albertville, AL'],
        "Alaska":['Anchorage, AK', 'Fairbanks, AK'] }
    global Zip
    Zip = [
    # Alaska
        # Anchorage, AK
        [['99501'],['99502'],['99503'],['99504'],['99505'],['99506'],['99507'],['99508'],['99509'],['99510'],['99511'],['99513'],['99514'],               ['99515'],['99516'],['99517'],['99518'],['99519'],['99520'],['99521'],['99522'],['99523'],['99524'],['99529'],['99530'],['99540'],               ['99567'],['99577'],['99587'],['99599'],['99629'],['99645'],['99652'],['99654'],['99667'],['99674'],['99676'],['99683'],['99687'],               ['99688'],['99694'],['99695']],    
        # Fairbanks, AK
        [['99701'],['99702'],['99703'],['99705'],['99706'],['99707'],['99708'],['99709'],['99710'],['99711'],['99712'],['99714'],['99716'],               ['99725'],['99775'],['99790']],

    # Alabama
        # Albertville, AL
        [['wefwe'],['99502'],['99503'],['99504'],['99505'],['99506'],['99507'],['99508'],['99509'],['99510'],['99511'],['99513'],['99514'],['99515'],['99516'],['99517'],['99518'],['99519'],['99520'],['99521'],['99522'],['99523'],['99524'],['99529'],['99530'],['99540'],['99567'],['99577'],['99587'],['99599'],['99629'],['99645'],['99652'],['99654'],['99667'],['99674'],['99676'],['99683'],['99687'],['99688'],['99694'],['99695']] ]

If I were do build this for every State, CBSA and Zip, it would take a long time to do, require a lot of code and require possible maintenance. I have instead saved off a pickled dataframe that sources these three fields from an Oracle table. This dataframe looks like the following:

enter image description here

On this website, I was able to find a way to take a dataframe and turn it into a nested dictionary.

GeoHierDict = {k: f.groupby('CBSA_NAME')['ZIP_CODE'].apply(list).to_dict()
                for k, f in GeoHier.groupby('STATE')}

Here is a sample of its output:

enter image description here

What I am trying to do is find a way to adjust the below tkinter script so that it references the nested GeoHierDict dictionary instead of the GeoLoad() function made up of both a dictionary and a nested list. The GeoHierDict dictionary is all setup the way I want it, but I need to adjust the below script to account for it. It is important that the comboboxes filling according to its parent. Here is the script, that works with the previous method, that I am trying to adjust to the nested dictionary method.

Any help or insight would be greatly appreciated.

import tkinter as tk
from tkinter import ttk

GeoLoad() 

lst = [x for y in list(State.values()) for x in y]


def change_dropdown(*args):

    print("Chosen brand " + tkvar.get())

    if args[0] == 'PY_VAR0':
        for x, y in State.items():
            if tkvar.get() == x:
                tkvar2.set(y[0])
                popupMenu2.configure(values=y)
        
    if args[0] == 'PY_VAR1':
        for x, y in zip(lst, Zip):
            if tkvar2.get() == x:            
                tkvar3.set(y[0])
                popupMenu3.configure(values=y)
        
    return
    
root = tk.Tk()
root.geometry('250x100')
font = ("Courier", 16, "bold")

tkvar = tk.StringVar(root)
tkvar.trace('w', change_dropdown)

tkvar2 = tk.StringVar(root)
tkvar2.trace('w', change_dropdown)

# -----------------------------------------------------------------------------------------------------------------------------------------------
# Geography:
# -----------------------------------------------------------------------------------------------------------------------------------------------
labelTop = tk.Label(root, text = "Geography",font='Helvetica 10 bold')
labelTop.grid(row=0, column=0, columnspan=2, sticky="ew")

labelTop = tk.Label(root, text = "Select a State:")
labelTop.grid(row=1, column=0, sticky=tk.W)
popupMenu1 = ttk.Combobox(root, textvariable=tkvar, values=list(State.keys()))
popupMenu1.grid(row=1, column=1)

labelTop = tk.Label(root, text = "Select a CBSA:")
labelTop.grid(row=2, column=0, sticky=tk.W)
popupMenu2 = ttk.Combobox(root, textvariable=tkvar2, values=[])
popupMenu2.grid(row=2, column=1)

tkvar3 = tk.StringVar(root)
labelTop = tk.Label(root, text = "Select a Zip Code:")
labelTop.grid(row=3, column=0, sticky=tk.W)
popupMenu3 = ttk.Combobox(root, textvariable=tkvar3, values=[])
popupMenu3.grid(row=3, column=1)

root.mainloop()

The end result should still look something like this:

enter image description here

Update 1 Here is the picked code that I used to create the the dataframe:

#---------------------------------------------------------------------------------------------------------------------------
# Geography Hierarchy:
#---------------------------------------------------------------------------------------------------------------------------
print("Querying Geography Hierarchy table...")

GeoHierQuery = """
SELECT DISTINCT
STATE, CBSA_NAME, ZIP_CODE
FROM SRC_TABLE

ORDER BY STATE, CBSA_NAME, ZIP_CODE
"""

df_GeoHierQuery = pd.read_sql(GeoHierQuery, con=conn);
# print(df_GeoHierQuery)

df_GeoHierQuery.to_pickle(r'C:\Users\USER123\df_GeoHierQuery.pkl');

GeoHier = pd.read_pickle(r'C:\Users\USER123\df_GeoHierQuery.pkl');
# print(GeoHier)

GeoHierDict = {k: f.groupby('CBSA_NAME')['ZIP_CODE'].apply(list).to_dict()
                for k, f in GeoHier.groupby('STATE')}
# GeoHierDict["CO"]["BOULDER, CO"]

print("Geography Hierarchy table saved")

The source is tied to an Oracle table. If you are just trying to get a dataframe to test against, below is a script that will yield that result with the initial geographical sample mentioned earlier:

df_GeoHier = {'STATE': ['AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL'], 'CBSA_NAME': ['Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL'], 'ZIP_CODE': ['99501','99502','99503','99504','99505','99506','99507','99508','99509','99510','99511','99513','99514','99515','99516','99517','99518','99519','99520','99521','99522','99523','99524','99529','99530','99540','99567','99577','99587','99599','99629','99645','99652','99654','99667','99674','99676','99683','99687','99688','99694','99695','99701','99702','99703','99705','99706','99707','99708','99709','99710','99711','99712','99714','99716','99725','99775','99790','35016','35031','35087','35175','35747','35754','35755','35760','35769','35776','35950','35951','35952','35956','35957','35962','35964','35975','35976','35980']}
df = pd.DataFrame(data=df_GeoHier)
df

Update 2 Below is the full script that I am currently working with:

import pandas as pd; import tkinter as tk; from tkinter import ttk;

df_GeoHier = {'STATE': ['AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL'], 'CBSA_NAME': ['Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL'], 'ZIP_CODE': ['99501','99502','99503','99504','99505','99506','99507','99508','99509','99510','99511','99513','99514','99515','99516','99517','99518','99519','99520','99521','99522','99523','99524','99529','99530','99540','99567','99577','99587','99599','99629','99645','99652','99654','99667','99674','99676','99683','99687','99688','99694','99695','99701','99702','99703','99705','99706','99707','99708','99709','99710','99711','99712','99714','99716','99725','99775','99790','35016','35031','35087','35175','35747','35754','35755','35760','35769','35776','35950','35951','35952','35956','35957','35962','35964','35975','35976','35980']}
df = pd.DataFrame(data=df_GeoHier)
df

import tkinter as tk
from tkinter import ttk

# GeoLoad() 

lst = [x for y in list(State.values()) for x in y]


def change_dropdown(*args):

    if args[0] == 'PY_VAR0':
        for x, y in State.items():
            if tkvar.get() == x:
                tkvar2.set(y[0])
                popupMenu2.configure(values=y)

    if args[0] == 'PY_VAR1':
        for x, y in GeoHierDict.items():
            if tkvar2.get() == list(y.keys())[0]:            
                tkvar3.set(list(y.values())[0][0])
                popupMenu3.configure(values=list(y.values())[0])
        
    return
    
root = tk.Tk()
root.geometry('250x100')
font = ("Courier", 16, "bold")

tkvar = tk.StringVar(root)
tkvar.trace('w', change_dropdown)

tkvar2 = tk.StringVar(root)
tkvar2.trace('w', change_dropdown)

# -----------------------------------------------------------------------------------------------------------------------------------------------
# Geography:
# -----------------------------------------------------------------------------------------------------------------------------------------------
labelTop = tk.Label(root, text = "Geography",font='Helvetica 10 bold')
labelTop.grid(row=0, column=0, columnspan=2, sticky="ew")

labelTop = tk.Label(root, text = "Select a State:")
labelTop.grid(row=1, column=0, sticky=tk.W)
popupMenu1 = ttk.Combobox(root, textvariable=tkvar, values=list(State.keys()))
popupMenu1.grid(row=1, column=1)

labelTop = tk.Label(root, text = "Select a CBSA:")
labelTop.grid(row=2, column=0, sticky=tk.W)
popupMenu2 = ttk.Combobox(root, textvariable=tkvar2, values=[])
popupMenu2.grid(row=2, column=1)

tkvar3 = tk.StringVar(root)
labelTop = tk.Label(root, text = "Select a Zip Code:")
labelTop.grid(row=3, column=0, sticky=tk.W)
popupMenu3 = ttk.Combobox(root, textvariable=tkvar3, values=[])
popupMenu3.grid(row=3, column=1)

root.mainloop()

Upvotes: 1

Views: 88

Answers (1)

JacksonPro
JacksonPro

Reputation: 3275

Here use this:

import pandas as pd
import tkinter as tk
from tkinter import ttk

df_GeoHier = {'STATE': ['AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AK','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL','AL'], 'CBSA_NAME': ['Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Anchorage, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Fairbanks, AK', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL', 'Albertville, AL'], 'ZIP_CODE': ['99501','99502','99503','99504','99505','99506','99507','99508','99509','99510','99511','99513','99514','99515','99516','99517','99518','99519','99520','99521','99522','99523','99524','99529','99530','99540','99567','99577','99587','99599','99629','99645','99652','99654','99667','99674','99676','99683','99687','99688','99694','99695','99701','99702','99703','99705','99706','99707','99708','99709','99710','99711','99712','99714','99716','99725','99775','99790','35016','35031','35087','35175','35747','35754','35755','35760','35769','35776','35950','35951','35952','35956','35957','35962','35964','35975','35976','35980']}
df = pd.DataFrame(data=df_GeoHier)


def change_dropdown(*args):
    
    if args[0] == 'PY_VAR0':
        for x, y in GeoHierDict.items():
            if tkvar.get() == x:
                tkvar2.set(list(y.keys())[0])
                popupMenu2.configure(values=list(y.keys()))

    if args[0] == 'PY_VAR1':
        for x, y in GeoHierDict.items():
            for key, value in y.items():
                if tkvar2.get() == key:            
                    tkvar3.set(value[0])
                    popupMenu3.configure(values=value)
            
    return
    
root = tk.Tk()
root.geometry('250x100')
font = ("Courier", 16, "bold")

tkvar = tk.StringVar(root)
tkvar.trace('w', change_dropdown)

tkvar2 = tk.StringVar(root)
tkvar2.trace('w', change_dropdown)

GeoHierDict = {k: f.groupby('CBSA_NAME')['ZIP_CODE'].apply(list).to_dict()
                for k, f in df.groupby('STATE')}

labelTop = tk.Label(root, text = "Geography",font='Helvetica 10 bold')
labelTop.grid(row=0, column=0, columnspan=2, sticky="ew")

labelTop = tk.Label(root, text = "Select a State:")
labelTop.grid(row=1, column=0, sticky=tk.W)
popupMenu1 = ttk.Combobox(root, textvariable=tkvar, values=list(set(df['STATE'])))
popupMenu1.grid(row=1, column=1)

labelTop = tk.Label(root, text = "Select a CBSA:")
labelTop.grid(row=2, column=0, sticky=tk.W)
popupMenu2 = ttk.Combobox(root, textvariable=tkvar2, values=[])
popupMenu2.grid(row=2, column=1)

tkvar3 = tk.StringVar(root)
labelTop = tk.Label(root, text = "Select a Zip Code:")
labelTop.grid(row=3, column=0, sticky=tk.W)
popupMenu3 = ttk.Combobox(root, textvariable=tkvar3, values=[])
popupMenu3.grid(row=3, column=1)

root.mainloop()

Upvotes: 1

Related Questions