Using Geopy to place (tkintermapview) Markers on Addresses that are pulled from a Spreadsheet

Question:

I am attempting to get Addresses from a Spreadsheet..
Convert those Addresses to Latitude and Longitude..
Then Add Markers to those Coordinates on a TkinterMapView Map.

I used openpyxl to make a Workbook:

wB = load_workbook('HoldingCats(1).xlsx')
wS = wB.active
column_b = wS['B']

Loop through the Workbook and print out Addresses. Setting the cells in "Column B" as function AddressCellB:

column_b = wS['B']

for cell in column_b:
    AddressCellB = cell.value
    print(AddressCellB)

Which all works fine and prints the addresses out…

But When I attempt to run function AddressCellB in .geocode() to get .address, .latitude, and .longitude…

for cell in column_b:
    AddressCellB = cell.value
    print(AddressCellB)

    loc = Nominatim(user_agent="Jimmy Wilson")

    getLoc = loc.geocode(AddressCellB, timeout=None)


contactName = getLoc.address
lat1 = getLoc.latitude
long1 = getLoc.longitude 

Marker1 = MAP.set_marker( lat1, long1, contactName)

I get an error:

    lat1 = getLoc.latitude
           ^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'address'

Am I approaching this weird?

Why wont the AddressCellB function return .address, .latitude, .longitude from .geocode()?

Is there a better way to pull the list of Addresses from Spreadsheet, Covert Addresses to Coordinates, and establish a Marker (in tkintermapview) for each Address?

TRACEBACK:

Traceback (most recent call last):   File "/Users/jawn/Desktop/EXcel/Excel2Me.py", line 377, in <module>
    contactName = getLoc.address
                  ^^^^^^^^^^^^^^ AttributeError: 'NoneType' object has no attribute 'address'

DISCUSSED CODE:

wB = load_workbook('HoldingCats(1).xlsx')
wS = wB.active
column_b = wS['B']

for cell in column_b:
    AddressCellB = cell.value
    print(AddressCellB)

    loc = Nominatim(user_agent="Jimmy Wilson")

    getLoc = loc.geocode(AddressCellB, timeout=None)


contactName = getLoc.address
lat1 = getLoc.latitude
long1 = getLoc.longitude 

Marker1 = MAP.set_marker( lat1, long1, contactName)

FULL CODE:

import customtkinter as ctk
import tkinter as tk
from tkinter import *
from tkinter import ttk
from tkintermapview import TkinterMapView
from PIL import Image, ImageTk
from CTkSpinbox import *
import openpyxl
from openpyxl.workbook import Workbook
from openpyxl import load_workbook
from geopy.geocoders import Nominatim
import googlemaps
from datetime import datetime

WholeApp = ctk.CTk()
WholeApp.title("Locations!")
WholeApp.geometry("1400x900")

#  DEF  ##############################################
def slide(e):
    MAP.set_zoom(Map_Slider.get())
def mutton():
    MAP.set_address(mapEntry.get())
def theme_stuff():
    pass
def load_SetData():
    path = "LocationsMM.xlsx"
    workbook = openpyxl.load_workbook(path)
    sheet = workbook.active
    list_values = list(sheet.values)
    for col_name in list_values[0]:
        SetTreeView.heading("#1", text="Set")
        SetTreeView.heading("#2", text="Business")
        SetTreeView.heading("#3", text="Address")
        SetTreeView.heading("#4", text="Shoot Date")
        SetTreeView.heading("#5", text="BG Count")
        SetTreeView.heading("#6", text="Notes")

        #SetTreeView.heading(col_name, text=col_name)
    for value_tuple in list_values[1:]:
        SetTreeView.insert('', tk.END, values=value_tuple)
def load_HolCatData():
    path2 = "HoldingCats(1).xlsx"
    workbook2 = openpyxl.load_workbook(path2)
    sheet2 = workbook2.active
    list_values2 = list(sheet2.values)
    for col_name2 in list_values2[0]:
        HolCatTreeView.heading("#1", text ="Name")
        HolCatTreeView.heading("#2", text ="Address")
        HolCatTreeView.heading("#3", text ="Contact")
        HolCatTreeView.heading("#4", text ="SQFT")
        HolCatTreeView.heading("#5", text ="$$$")
    for value_tuple2 in list_values2[1:]:
        HolCatTreeView.insert('',tk.END, values = value_tuple2)
def calc():
    calcRoot = ctk.CTk()
    calcRoot.title("Something Doesnt Add Up")
    
    calcEntry = ctk.CTkEntry(calcRoot, width=150, height=50)
    calcEntry.grid(row=0, column=0, pady=5, padx=5, columnspan=3)
    
    button_1 = ctk.CTkButton(calcRoot, text="1", corner_radius=50 ,width=30, height=30)
    button_1.grid(row=1, column=0, pady=3, padx=3)
    button_2 = ctk.CTkButton(calcRoot, text="2", corner_radius=50 ,width=30, height=30)
    button_2.grid(row=1, column=1, pady=3, padx=3)
    button_3 = ctk.CTkButton(calcRoot, text="3", corner_radius=50 ,width=30, height=30)
    button_3.grid(row=1, column=2, pady=3, padx=3)
    
    button_4 = ctk.CTkButton(calcRoot, text="4", corner_radius=50 ,width=30, height=30)
    button_4.grid(row=2, column=0, pady=3, padx=3)
    button_5 = ctk.CTkButton(calcRoot, text="5", corner_radius=50 ,width=30, height=30)
    button_5.grid(row=2, column=1, pady=3, padx=3)
    button_6 = ctk.CTkButton(calcRoot, text="6", corner_radius=50 ,width=30, height=30)
    button_6.grid(row=2, column=2, pady=3, padx=3)
    
    button_7 = ctk.CTkButton(calcRoot, text="7", corner_radius=50 ,width=30, height=30)
    button_7.grid(row=3, column=0, pady=3, padx=3)
    button_8 = ctk.CTkButton(calcRoot, text="8", corner_radius=50 ,width=30, height=30)
    button_8.grid(row=3, column=1, pady=3, padx=3)
    button_9 = ctk.CTkButton(calcRoot, text="9", corner_radius=50 ,width=30, height=30)
    button_9.grid(row=3, column=2, pady=3, padx=3)
    
    button_E = ctk.CTkButton(calcRoot, text="=", corner_radius=50 ,width=30, height=30)
    button_E.grid(row=4, column=0, pady=3, padx=3)
    button_0 = ctk.CTkButton(calcRoot, text="0", corner_radius=50 ,width=30, height=30)
    button_0.grid(row=4, column=1, pady=3, padx=3)
    button_S = ctk.CTkButton(calcRoot, text="-", corner_radius=50 ,width=30, height=30)
    button_S.grid(row=4, column=2, pady=3, padx=3)

#  LABEL  #
LocationsLabel = ctk.CTkLabel(WholeApp, 
                         text="Locations!",
                         font=("cochin", 55),
                         text_color="white",
                         
                         )
LocationsLabel.grid(row=0, column=1, pady=2, padx=2)

# THEME COMBO #
theme_change = ctk.CTkComboBox(WholeApp, values=["Dark", "Light", "Sports", "Elmo"], command=theme_stuff)
theme_change.grid(row=0, column=0, pady=5, padx=5)
# Excel Combo #
def ExcelFileChoice():
    pass
excel_combo = ctk.CTkComboBox(WholeApp, values = ["Set", "HolCat"], command=ExcelFileChoice)
excel_combo.grid(row=0, column=2, pady=2, padx=2)

#  TAB FRAME1  ##############################################
#  SEARCH TAB #
TabFrame1=ctk.CTkTabview(WholeApp, 
                        width=55,
                        height=300,
                        corner_radius=10,  
                        border_width=1,
                        segmented_button_selected_color="teal",
                        segmented_button_selected_hover_color="gray",
                        text_color="black"
                    )
TabFrame1.grid(row=1, column=0, pady=5, padx=(50,1))
Tab_search = TabFrame1.add("Search")
SetSearch = ctk.CTkEntry(Tab_search, 
                             width=185,
                             placeholder_text="set",
                             font=('cochin', 15),
                             corner_radius=10,
                             border_width=1,
                             )
SetSearch.insert(0, "Set")
SetSearch.bind("<FocusIn>", lambda e: SetSearch.delete('0', 'end'))
SetSearch.grid(row=0, column=0, columnspan=2, pady=3, padx=5)
BusinessSearch = ctk.CTkEntry(Tab_search, 
                             width=185,
                             placeholder_text=("Address"),
                             font=('cochin', 15),
                             corner_radius=10,
                             border_width=1,
                             )
BusinessSearch.insert(0, "Business")
BusinessSearch.bind("<FocusIn>", lambda e: BusinessSearch.delete('0', 'end'))
BusinessSearch.grid(row=1, column=0, columnspan=2, pady=3, padx=5)
AddressSearch = ctk.CTkEntry(Tab_search, 
                             width=185,
                             placeholder_text=("Shoot Date"),
                             font=('cochin', 15),
                             corner_radius=10,
                             border_width=1,
                             )
AddressSearch.insert(0, "Address")
AddressSearch.bind('<FocusIn>', lambda e: AddressSearch.delete('0', 'end'))
AddressSearch.grid(row=2, column=0, columnspan=2, pady=3, padx=5)
ShootDateSearch = ctk.CTkEntry(Tab_search, 
                             width=185,
                             placeholder_text=("Shoot Date"),
                             font=('cochin', 15),
                             corner_radius=10,
                             border_width=1,
                             )
ShootDateSearch.insert(0, "Shoot Date")
ShootDateSearch.bind('<FocusIn>', lambda e: ShootDateSearch.delete('0', 'end'))
ShootDateSearch.grid(row=3, column=0, columnspan=2, pady=3, padx=5)
bg_label = ctk.CTkLabel(Tab_search, text="   BG",
                        font=("cochin", 15),
                        text_color="white",
                        )
bg_label.grid(row=4, column=0)
def print_label(count):
    print(count)
spin_var = ctk.IntVar()
BGSearch = CTkSpinbox(Tab_search,
                      font=("cochin", 15),
                      start_value=50, 
                      min_value=0, 
                      max_value=500, 
                      variable=spin_var,
                      command=print_label
                             )
BGSearch.grid(row=4, column=1, pady=3, padx=5)
NotesSearch = ctk.CTkEntry(Tab_search, 
                             width=185,
                             placeholder_text=("Notes"),
                             font=('cochin', 15),
                             corner_radius=10,
                             border_width=1,
                             )
NotesSearch.grid(row=5, column=0, columnspan=2, pady=3, padx=5)
SearchButton = ctk.CTkButton(Tab_search, 
                             font=("cochin",18),
                             text="Search",
                             text_color="black",
                             fg_color="teal",
                             corner_radius=10,
                             width=100,
                             hover_color="black"
                             )
SearchButton.grid(row=6, column=0, columnspan=2, pady=(5,5), padx=5)
##############################################################

#  ADD TAB  #
Tab_Add = TabFrame1.add("Add")
SetAdd = ctk.CTkEntry(Tab_Add, 
                             width=185,
                             placeholder_text=("Set"),
                             font=('cochin', 15),
                             corner_radius=10,
                             border_width=1,
                             )
SetAdd.grid(row=0, column=0, pady=3, padx=5)
SetAdd.insert(0, "Set")
SetAdd.bind("<FocusIn>", lambda e: SetAdd.delete('0', 'end'))
AddressAdd = ctk.CTkEntry(Tab_Add, 
                             width=185,
                             placeholder_text=("Address"),
                             font=('cochin', 15),
                             corner_radius=10,
                             border_width=1,
                             )
AddressAdd.grid(row=1, column=0, pady=3, padx=5)
ShootDateAdd = ctk.CTkEntry(Tab_Add, 
                             width=185,
                             placeholder_text=("Shoot Date"),
                             font=('cochin', 15),
                             corner_radius=10,
                             border_width=1,
                             )
ShootDateAdd.grid(row=2, column=0, pady=3, padx=5)
def print_label1(count1):
    print(count1)
spin_var1 = ctk.IntVar()
BGAdd = CTkSpinbox(Tab_Add,
                   start_value=50,
                   min_value=0,
                   max_value=500,
                   variable=spin_var1,
                   command=print_label1,
                   font=('cochin', 15),
                             )
BGAdd.grid(row=3, column=0, pady=3, padx=5)
NotesAdd = ctk.CTkEntry(Tab_Add, 
                             width=185,
                             placeholder_text=("Notes"),
                             font=('cochin', 15),
                             corner_radius=10,
                             border_width=1,
                             )
NotesAdd.grid(row=4, column=0, pady=3, padx=5)
AddButton = ctk.CTkButton(Tab_Add, 
                             font=("cochin",18),
                             text="Search",
                             text_color="black",
                             fg_color="teal",
                             corner_radius=10,
                             width=100,
                             hover_color="black"
                             )
AddButton.grid(row=5, column=0, pady=(5,5), padx=5)
###################################################

#  TOOLS TAB ######################
Tab_Tools = TabFrame1.add("Tools")
ButtonCalc = ctk.CTkButton(Tab_Tools, 
                           font=("cochin",15),
                           text="Calc",
                           fg_color="teal",
                           corner_radius=10,
                           border_color="black",
                           border_width=1,
                           hover_color="black",
                           command=calc
                             )
ButtonCalc.grid(row=0, column=0, pady=5, padx=5)
###################################################

#  EXCEL TAB FRAME ###############################################
treeFrame=ctk.CTkTabview(WholeApp, 
                    width=800, 
                    height=300, 
                    corner_radius=10,  
                    border_width=1,
                    )
treeFrame.grid(row=1, column=1, pady=1, padx=1, columnspan=3)
# SET TAB #
SetTab = treeFrame.add("Set")
SetScroll = ctk.CTkScrollbar(SetTab,
                              button_color="teal",
                              fg_color="black"
                              )
SetScroll.pack(side="right", fill="y")
cols = ("SET", "BUSINESS", "ADDRESS", "SHOOT DATE", "BG COUNT", "NOTES")
SetTreeView = ttk.Treeview(SetScroll,
                        yscrollcommand=SetScroll.set,
                        columns=cols,
                        height=12
                        )
SetTreeView['show'] = 'headings'
SetTreeView.column("SET", width=175)
SetTreeView.column("BUSINESS", width=250)
SetTreeView.column("ADDRESS", width=250)
SetTreeView.column("SHOOT DATE", width=150)
SetTreeView.column("BG COUNT", width=50)
SetTreeView.column("NOTES", width=100)
SetTreeView.pack()
SetScroll.configure(command=SetTreeView.yview)
load_SetData()
# HolCat #
HolCatTab = treeFrame.add("Holcat")
HolCatScroll = ctk.CTkScrollbar(HolCatTab,
                                button_color="teal",
                                fg_color="black"
                                )
HolCatScroll.pack(side="right", fill="y")
cols2 = ("NAME", "ADDRESS", "CONTACT", "SQFT", "$")
HolCatTreeView = ttk.Treeview(HolCatScroll,
                              yscrollcommand=HolCatScroll.set,
                              columns=cols2,
                              height=12
                              )
HolCatTreeView["show"] = 'headings'
HolCatTreeView.column("ADDRESS", width=250)
HolCatTreeView.column("CONTACT", width=275)
HolCatTreeView.column("SQFT", width=100)
HolCatTreeView.column("$", width=150)
HolCatTreeView.pack()
HolCatScroll.configure(command=HolCatTreeView.yview)
load_HolCatData()

#  MAP_FRAME  ######################
mapEntryFrame=ctk.CTkTabview(WholeApp, 
                    width=800, 
                    height=200, 
                    corner_radius=10,  
                    border_width=1,
                    text_color="black",
                    segmented_button_selected_color="teal",
                    segmented_button_selected_hover_color="gray"
                    )
mapEntryFrame.grid(row=2, column=0, pady=1, padx=(50,5), columnspan=3, sticky="nsew")
TabMap = mapEntryFrame.add("Map")
mapEntry = ctk.CTkEntry(TabMap,
                        width=200,
                        placeholder_text="Address",
                        font=("cochin", 13),
                        corner_radius=10,
                        )
mapEntry.grid(row=0, column=1, pady=1, padx=5, sticky="nsew")
mapButton = ctk.CTkButton(TabMap,
                          text="Search",
                          fg_color="teal",
                          font=("cochin", 13),
                          text_color="black",
                          corner_radius=10,
                          command=mutton,
                          width=100,
                          hover_color="black"
                          )
mapButton.grid(row=0, column=0, pady=1, padx=1)
MAP = TkinterMapView(TabMap, 
                         width=750,
                         height=300,
                         corner_radius=15
                         )
MAP.grid(row=1, column=1, pady=5, padx=5, columnspan=2)
MAP.set_address("Manhattan")
MAP.set_zoom(12)

wB = load_workbook('HoldingCats(1).xlsx')
wS = wB.active
column_b = wS['B']

for cell in column_b:
    AddressCellB = cell.value
    print(AddressCellB)

    loc = Nominatim(user_agent="Jimmy Wilson")

    getLoc = loc.geocode(AddressCellB)

contactName = getLoc.address
lat1 = getLoc.latitude
long1 = getLoc.longitude 

Marker1 = MAP.set_marker( lat1, long1, contactName)

Map_Slider = ctk.CTkSlider(TabMap,
                           from_=4,
                           to=20,
                           orientation=tk.VERTICAL,
                           command=slide,
                           button_color="teal",
                           fg_color="black",
                           progress_color="black",
                           button_hover_color="black"
                           )
Map_Slider.grid(row=1, column=0, pady=5, padx=5)
TabEntry = mapEntryFrame.add("Entry")
ButtonEntry = ctk.CTkButton(TabEntry, 
                            width=100, 
                            text="Note", 
                            font=("cochin", 15),
                            text_color="black",
                            fg_color="teal",
                            corner_radius=10,
                            hover_color="black"
                            )
ButtonEntry.grid(row=0, column=0, pady=5, padx=5)
TextBoxFrame = ctk.CTkTextbox(TabEntry, 
                            width=600, 
                            height=200, 
                            border_width=1,  
                            corner_radius=15,
                            )
TextBoxFrame.grid(row=0, column=1, pady=10, padx=10)

WholeApp.mainloop()

UPDATE EDIT: Added Marker and Geo Functions within for loop. To try and get the loop to add a new Marker each loop.
and I am still getting the error: ‘NoneType’ object has no attribute ‘address’.


MAP = TkinterMapView(TabMap, 
                         width=750,
                         height=300,
                         corner_radius=15
                         )
MAP.grid(row=1, column=1, pady=5, padx=5, columnspan=2)
MAP.set_address("Manhattan")
MAP.set_zoom(12)

wB = load_workbook('HoldingCats(2).xlsx')
wS = wB.active
column_b = wS['B']
#for cell in column_b:
#    AddressCellB = cell.value
for i, cell in enumerate(column_b, start=1):
    AddressCellB2 = i, cell.value
    print(AddressCellB2)

    ic(AddressCellB2)

    loc = Nominatim(user_agent="Jimmy Wilson")
    getLoc = loc.geocode(AddressCellB2, timeout=None)

    contactName = 1 #getLoc.address
    lat1 = 1 #getLoc.latitude
    long1 = 1 #getLoc.longitude 

    Marker1 = MAP.set_marker( lat1, long1, contactName)

Map_Slider = ctk.CTkSlider(TabMap,...
Map_Slider.grid(row=1, column=0, pady=5, padx=5)

UPDATE TRACEBACK:

AttributeError: 'PhotoImage' object has no attribute '_PhotoImage__photo'
Traceback (most recent call last):
  File "/Users/jawn/Desktop/banana()/EXcel/Excel2Me.py", line 380, in <module>
    contactName = getLoc.address
                  ^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'address'
Asked By: LaLuna

||

Answers:

As far as I can see, other than only looking up the last address in the list of addresses in column B, your problem is due with the lookup of the address(s) and not with the reading the them from Excel.

Therefore try breaking down your code to simpler segments for debugging. The first thing you need to do is confirm the lookup of one address only;

For Example, try running the following code;
You can use the address I have included on the first run and if that works then change it to an address you are trying to look up, the last address in Column B is a good start.
This code sample will print the ‘getLoc’ object type and each attribute and value for the same.
If the getloc type is wrong or you still get an error for the attributes, ‘address’. ‘latitude’ and ‘longitude’ are not shown then you probably need to ensure you have the latest version(s) of geopy installed.

from geopy.geocoders import Nominatim


AddressCellB = '225 Baker St NW, Atlanta, GA 30313, USA'
loc = Nominatim(user_agent="Jimmy Wilson")

getLoc = loc.geocode(AddressCellB, timeout=5)
print(f"getLoc object type: {type(getLoc)}")

getLoc_attrib_list = [x for x in dir(getLoc) if not x.startswith(('__','_')) and not callable(getattr(getLoc, x))]

for atty in getLoc_attrib_list:
        print(f"Attribute: {atty}, Value: {getattr(getLoc,atty)} ")

The output for the above should be;

getLoc object type: <class 'geopy.location.Location'>
Attribute: address, Value: Georgia Aquarium, 225, Baker Street Northwest, Atlanta, Fulton County, Georgia, 30313, United States 
Attribute: altitude, Value: 0.0 
Attribute: latitude, Value: 33.76326745 
Attribute: longitude, Value: -84.39511726814364 
Attribute: point, Value: 33 45m 47.7628s N, 84 23m 42.4222s W 
Attribute: raw, Value: {'place_id': 298584991, 'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright', 'osm_type': 'way', 'osm_id': 28912103, 'lat': '33.76326745', 'lon': '-84.39511726814364', 'class': 'tourism', 'type': 'aquarium', 'place_rank': 30, 'importance': 0.39736292979669935, 'addresstype': 'tourism', 'name': 'Georgia Aquarium', 'display_name': 'Georgia Aquarium, 225, Baker Street Northwest, Atlanta, Fulton County, Georgia, 30313, United States', 'boundingbox': ['33.7623777', '33.7643007', '-84.3960032', '-84.3939931']} 

If all the above checks out OK then you can try reading your addresses from the Excel Sheet.
As mentioned when looping through the addresses then you need to process each address as its read.
You can read from the sheet and as you go (as you have in the mwe) or dump all the address from Column B into a list first and loop through that instead. It doesn’t really matter at this point, but after reading an address e.g.

for cell in column_b:
    AddressCellB = cell.value
    print(AddressCellB)

you must do something with AddressCellB otherwise you are looping to the next address and the previous AddressCellB is lost. So ultimately only the last address ) will be processed (since the loop ends the last value of AddressCellB will be the last read and the code ony then moves on to the address look up).
So you need to have the getLoc = loc.geocode(AddressCellB) lookup and subsequent ‘address’. ‘latitude’ and ‘longitude’ extraction in the same loop as that reading each cell in Column B.

Therefore your next test code would be something like

from openpyxl import load_workbook
from geopy.geocoders import Nominatim


wB = load_workbook('HoldingCats(2).xlsx')
wS = wB.active
column_b = wS['B']

for cell in column_b:
    AddressCellB = cell.value
    print(AddressCellB)

    loc = Nominatim(user_agent="Jimmy Wilson")

    getLoc = loc.geocode(AddressCellB, timeout=5)
    print(f"getLoc object type: {type(getLoc)}")

    getLoc_attrib_list = [x for x in dir(getLoc) if not x.startswith(('__','_')) and not callable(getattr(getLoc, x))]

    for atty in getLoc_attrib_list:
            print(f"Attribute: {atty}, Value: {getattr(getLoc,atty)}")

    print('-------------------------------------')

If that test is reading and displaying the required data for each address in the Excel sheet then you can remove the attribute loop and just extract those you require and go onto adding the mapping etc.

Answered By: moken