TypeError: ‘int’ object has no attribute ‘log’ when plotting log-transformed sequence in Matplotlib

I am working on a Python project where I calculate and plot a graph of Aliquot sequence. I created a list.py script that displays the numbers in the .db file and it turns out the numbers are correctly computed and saved to a database. However, when I try to plot the sequence using graph.py, I encounter the following error:

Exception in Tkinter callback
AttributeError: 'int' object has no attribute 'log'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:Python312Libtkinter__init__.py", line 1967, in __call__
    return self.func(*args)
           ^^^^^^^^^^^^^^^^
  File "graph.py", line 94, in plot_graph    
    plot_sequence(sequence, log_scale=True, log_base=log_base)
  File "graph.py", line 35, in plot_sequence 
    transformed_sequence = np.log(sequence) / np.log(log_base)
                           ^^^^^^^^^^^^^^^^
TypeError: loop of ufunc does not support argument 0 of type int which has no callable log method

Here is the graph.py script:

import os
import sqlite3
import tkinter as tk
from tkinter import filedialog, messagebox
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation

def fetch_sequence_from_db(db_path):
    try:
        conn = sqlite3.connect(db_path)
        c = conn.cursor()
        c.execute("SELECT sequence FROM sequences")
        sequence_str = c.fetchone()[0]
        sequence = [int(x) for x in sequence_str.strip('][').split(', ')]
        conn.close()
        return sequence
    except Exception as e:
        messagebox.showerror("Error", f"Failed to read database: {e}")
        return None

def format_scientific(number):
    exponent = int(np.log10(number))
    base = number / 10**exponent
    return f"{base:.1f} x 10^{exponent}"

def plot_sequence(sequence, log_scale=False, log_base=None):
    fig, ax = plt.subplots(figsize=(10, 5))

    if log_scale and log_base:
        transformed_sequence = np.log(sequence) / np.log(log_base)
        ylabel = f"log_{log_base}(Number)"
    else:
        transformed_sequence = sequence
        ylabel = "Number"

    ax.set_title("Aliquot Sequence")
    ax.set_xlabel("Iteration")
    ax.set_ylabel(ylabel)
    ax.grid(True)
    ax.set_xlim(0, len(transformed_sequence) - 1)
    
    line, = ax.plot([], [], linestyle='-', color='b')

    def update(frame):
        line.set_data(range(frame + 1), transformed_sequence[:frame + 1])
        ax.relim()
        ax.autoscale_view()
        return line,

    ani = FuncAnimation(fig, update, frames=len(transformed_sequence), blit=True, interval=10, repeat=False)
    
    # Find and format the largest number
    largest_number = max(sequence)
    formatted_largest_number = format_scientific(largest_number)
    
    # Display the largest number on the graph
    plt.text(0.5, 1.05, f"Largest number: {formatted_largest_number}", ha='center', va='center', transform=ax.transAxes, fontsize=12)
    
    plt.subplots_adjust(left=0.05, right=0.95)  # Adjusting the left margin to make the 0th iteration close to the border
    plt.show()

def select_file():
    file_path = filedialog.askopenfilename(
        initialdir=os.path.join(os.path.dirname(os.path.abspath(__file__)), "Number_Sequences"),
        title="Select a Database File",
        filetypes=(("Database Files", "*.db"), ("All Files", "*.*"))
    )
    if file_path:
        entry_file_path.delete(0, tk.END)
        entry_file_path.insert(0, file_path)

def plot_graph():
    db_path = entry_file_path.get()
    if not os.path.exists(db_path):
        messagebox.showerror("Error", "File not found.")
        return

    sequence = fetch_sequence_from_db(db_path)
    if not sequence:
        return

    if var_log_transform.get():
        try:
            log_base = float(entry_log_base.get())
        except ValueError:
            messagebox.showerror("Error", "Invalid log base.")
            return
        plot_sequence(sequence, log_scale=True, log_base=log_base)
    else:
        plot_sequence(sequence, log_scale=False)

# Setting up the Tkinter window
root = tk.Tk()
root.title("Aliquot Sequence Grapher")

frame = tk.Frame(root)
frame.pack(padx=10, pady=10)

label_file_path = tk.Label(frame, text="Database File:")
label_file_path.grid(row=0, column=0, sticky="e")

entry_file_path = tk.Entry(frame, width=40)
entry_file_path.grid(row=0, column=1, padx=5)

button_browse = tk.Button(frame, text="Browse", command=select_file)
button_browse.grid(row=0, column=2, padx=5)

var_log_transform = tk.BooleanVar(value=True)
check_log_transform = tk.Checkbutton(frame, text="Log Transform", variable=var_log_transform)
check_log_transform.grid(row=1, column=0, columnspan=3)

label_log_base = tk.Label(frame, text="Log Base:")
label_log_base.grid(row=2, column=0, sticky="e")

entry_log_base = tk.Entry(frame, width=10)
entry_log_base.grid(row=2, column=1, padx=5, sticky="w")
entry_log_base.insert(0, "10")

button_plot = tk.Button(frame, text="Plot Graph", command=plot_graph)
button_plot.grid(row=3, column=0, columnspan=3, pady=10)

root.mainloop()

This is the list of numbers from the list.py. The number of the iteration is shown only in the list.py script:

1 : 276
2 : 396
3 : 696
4 : 1104
5 : 1872
6 : 3770
7 : 3790
8 : 3050
9 : 2716
10 : 2772
11 : 5964
12 : 10164
13 : 19628
14 : 19684
15 : 22876
16 : 26404
17 : 30044
18 : 33796
19 : 38780
20 : 54628
21 : 54684
22 : 111300
23 : 263676
24 : 465668
25 : 465724
26 : 465780
27 : 1026060
28 : 2325540
29 : 5335260
30 : 11738916
31 : 23117724
32 : 45956820
33 : 121129260
34 : 266485716
35 : 558454764
36 : 1092873236
37 : 1470806764
38 : 1471882804
39 : 1642613196
40 : 2737688884
41 : 2740114636
42 : 2791337780
43 : 4946860492
44 : 4946860548
45 : 9344070652
46 : 9344070708
47 : 15573451404
48 : 27078171764
49 : 27284104204
50 : 27410152084
51 : 27410152140
52 : 76787720100
53 : 220578719452
54 : 254903331620
55 : 361672366300
56 : 603062136740
57 : 921203207260
58 : 1381419996068
59 : 1395444575644
60 : 1395478688996
61 : 1395546402460
62 : 2069258468900
63 : 3065057872156
64 : 3277068463844
65 : 3429776547484
66 : 3597527970596
67 : 4028517592540
68 : 5641400009252
69 : 5641400009308
70 : 5641400009364
71 : 9709348326636
72 : 16331909651988
73 : 31948891146732
74 : 54770416120644
75 : 100509779504316
76 : 208751080955844
77 : 388416032284476
78 : 749365894850244
79 : 1414070378301756
80 : 2556878765995204
81 : 2556878765995260
82 : 6726041614128900
83 : 15626498692840700
84 : 23762659088671300
85 : 35168735451235260
86 : 78257359358590020
87 : 186897487211247036
88 : 340813223900632644
89 : 592585414385033916
90 : 1326583294186844484
91 : 2594892903616159356
92 : 4946738730471899844
93 : 8244565422068579772
94 : 13740942370114299844
95 : 13780400058385352252
96 : 13780400058385352308
97 : 14272557426581383244
98 : 14272557426581383300
99 : 21155073391000330684
100 : 21374326697892540932
101 : 22138822441861473292

I also have the same file but with only 70 iterations with the same numbers and it plots the graph just fine. Here is the main.py script that calculates the Aliquot Sequence if needed:

import os
import math
import sqlite3

# Function to get all divisors of a given number
def get_divisors(n):
    divisors = [1]
    for i in range(2, int(math.sqrt(n)) + 1):
        if n % i == 0:
            divisors.append(i)
            if i != n // i:
                divisors.append(n // i)
    if n > 1:
        divisors.append(n)
    return sorted(divisors)

# Function to calculate the sum of divisors for a given number
def sum_of_divisors(n):
    return sum(get_divisors(n)) - n

# Function to calculate the Aliquot Sequence for a given number
def aliquot_sequence(start_number, iterations=None):
    sequence = [start_number]
    current_iteration = 1

    while True:
        next_number = sum_of_divisors(sequence[-1])
        sequence.append(next_number)
        print(f"Iteration {current_iteration}: {next_number}")
        if next_number == 1 or next_number in sequence[:-1] or next_number == sum_of_divisors(next_number):
            break
        if iterations and current_iteration >= iterations:
            break
        current_iteration += 1

    return sequence

# Function to save the result to the database
def save_to_database(number, sequence, iterations=None, continue_from_file=None):
    current_dir = os.path.dirname(os.path.abspath(__file__))
    folder_name = os.path.join(current_dir, "Number Sequences")
    if not os.path.exists(folder_name):
        try:
            os.makedirs(folder_name)
        except OSError as e:
            print(f"Error creating folder: {e}")
            return
    
    if continue_from_file:
        db_file_path = continue_from_file
        original_name, _ = os.path.splitext(os.path.basename(continue_from_file))
        original_number, original_iterations = original_name.split('_')
        original_iterations = int(original_iterations)
        total_iterations = original_iterations + (len(sequence) - 1)
        if sequence[-1] == 1 or sequence[-1] in sequence[:-1] or sequence[-1] == sum_of_divisors(sequence[-1]):
            final_file_name = f"{number}.db"
        else:
            final_file_name = f"{number}_{total_iterations}.db"
        final_db_file_path = os.path.join(folder_name, final_file_name)
    else:
        if iterations:
            file_name = f"{number}_{iterations}.db"
        else:
            file_name = f"{number}.db"
        db_file_path = os.path.join(folder_name, file_name)

    try:
        conn = sqlite3.connect(db_file_path)
        c = conn.cursor()
        c.execute('''CREATE TABLE IF NOT EXISTS sequences (number INTEGER, sequence TEXT)''')
        if continue_from_file:
            c.execute('''SELECT sequence FROM sequences''')
            old_sequence_str = c.fetchone()[0]
            old_sequence = [int(x) for x in old_sequence_str.strip('][').split(', ')]
            combined_sequence = old_sequence + sequence[1:]  # Exclude the initial number from new sequence
            c.execute('''UPDATE sequences SET sequence = ? WHERE number = ?''', (str(combined_sequence), number))
        else:
            c.execute('''INSERT INTO sequences (number, sequence) VALUES (?, ?)''', (number, str(sequence)))
        conn.commit()
        conn.close()

        if continue_from_file and db_file_path != final_db_file_path:
            try:
                os.rename(db_file_path, final_db_file_path)
            except OSError as e:
                print(f"Error renaming file to final name: {e}")

    except sqlite3.Error as e:
        print(f"Database error: {e}")
        return

# Function to check if number exists in the database
def number_exists_in_database(number, iterations=None):
    current_dir = os.path.dirname(os.path.abspath(__file__))
    folder_name = os.path.join(current_dir, "Number Sequences")
    if os.path.exists(folder_name):
        for file in os.listdir(folder_name):
            if file.endswith(".db"):
                db_name, _ = os.path.splitext(file)
                split_name = db_name.split('_')
                db_number = int(split_name[0])
                db_iterations = None if len(split_name) == 1 else int(split_name[1])
                if db_number == number and db_iterations == iterations:
                    return True
    return False

# Main function
def main():
    # Get input from the user
    number = int(input("Enter a number to calculate its Aliquot Sequence: "))
    iterations = input("Enter 'auto' to calculate until stopped automatically, or enter the number of iterations: ")
    if iterations.lower() == 'auto':
        iterations = None
    else:
        iterations = int(iterations)

    continue_calculation = input("Do you want to continue calculation from where you left? (yes/no): ")
    if continue_calculation.lower() == 'yes':
        continue_from_file = input("Enter the file name to continue from: ")
        continue_from_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Number Sequences", continue_from_file)
        if not os.path.exists(continue_from_file):
            print("File not found.")
            return
        
        conn = sqlite3.connect(continue_from_file)
        c = conn.cursor()
        c.execute('''SELECT sequence FROM sequences''')
        sequence_str = c.fetchone()[0]
        sequence = [int(x) for x in sequence_str.strip('][').split(', ')]
        conn.close()
        start_number = sequence[-1]  # Start from the last number in the sequence
    else:
        continue_from_file = None
        start_number = number

    # Check if number exists in the database
    if number_exists_in_database(number, iterations):
        print("Sequence already exists in the database.")
        return
    
    # Calculate Aliquot Sequence
    new_sequence = aliquot_sequence(start_number, iterations)
    
    # Print the sequence
    print(f"Aliquot Sequence for {number}: {new_sequence}")
    
    # Save the sequence to the database
    save_to_database(number, new_sequence, iterations, continue_from_file)
    print("Sequence saved to database.")

if __name__ == "__main__":
    main()

Ensured log_base is converted to float before being used.

1

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật