Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Plot function
#1
Hi Everyone,
apologies my code is all over the place, however I am trying to bar chart plot the cycle time for each model selected. I want the chart to be in my main gui somwhere over to the right of my existing columns. I cannot get the code to work can someone please help me fix it?
import tkinter as tk
from tkinter import ttk
import math
from datetime import timedelta
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg



# Helper functions
def rgb_to_hex(r, g, b):
    return f'#{r:02x}{g:02x}{b:02x}'

def set_widget_bg_color(widget, bg_color, fg_color="black"):
    widget_class = widget.winfo_class()
    
    if widget_class == "Label":
        widget.config(bg=bg_color, fg=fg_color)
    elif widget_class == "Frame" or widget_class == "Toplevel":
        widget.config(bg=bg_color)
    elif widget_class == "Text":
        widget.config(bg=bg_color, fg=fg_color, insertbackground=fg_color)
    
    for child in widget.winfo_children():
        set_widget_bg_color(child, bg_color, fg_color)

def flash_red(widget, flash_count=5, interval=500):
    original_color = widget.cget("foreground")

    if flash_count % 2 == 0:
        widget.config(foreground=original_color)
    else:
        widget.config(foreground="red")

    if flash_count > 1:
        widget.after(interval, flash_red, widget, flash_count - 1, interval)

def format_duration(seconds):
    duration = timedelta(seconds=seconds)
    hours, remainder = divmod(duration.seconds, 3600)
    minutes, seconds = divmod(remainder, 60)
    return "{:02}:{:02}:{:02}".format(int(duration.days * 24 + hours), minutes, seconds)

def calculate_travel_time(travel_distance):
    return (
        (0.00185 * travel_distance + 0.00317 * (0.7717 + 4.004 * math.log(travel_distance)) + 0.0476) +
        (0.00184 * travel_distance + 0.00183 * (2.2157 + 3.8958 * math.log(travel_distance)) + 0.05467)
    )



def update_plot():
    plt.clf()  # Clear the previous plot
    
    models = [model_vars[col].get() for col in range(num_columns)]
    cycle_times = [cycle_time_labels[col]['text'] for col in range(num_columns)]
    
    plt.barh(models, [float(time.split(":")[0]) + float(time.split(":")[1])/60 + float(time.split(":")[2])/3600 for time in cycle_times])
    plt.xlabel("Cycle Time (hours)")
    plt.ylabel("Model")
    plt.title("Cycle Time Comparison")
    
    # Draw the plot onto the canvas
    canvas = FigureCanvasTkAgg(plt.gcf(), master=canvas_frame)
    canvas.draw()
    canvas.get_tk_widget().pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

def update_all_timings(col):
    # Call the functions to update timings for this column
    update_model_travel_times(col)
    calculate_cycle_time(col)
    update_plot()  # Call the function to update the plot






#Initialization of core data===============================================================
bg_color = rgb_to_hex(255, 205, 17)

models_data = {
    "Caterpillar LHD models": {
        "R1300G": ["DB 3.4", "DB 2.8", "DB 2.5", "DB 3.1"],
        "R1600H": ["DB 5.9", "DB 4.8", "DB 4.2", "DB 5.6"],
        "R1700": ["DB 5.7", "DB 6.1", "DB 6.6", "DB 7.5", "DB 8"],
        "R1700XE": ["DB 5.7", "DB 6.1", "DB 6.6", "DB 7.5"],
        "R1700G": ["DB 4.6", "DB 5", "DB 6.6", "DB 5.7", "DB 7.3", "DB 8.8"],
        "R2900G": ["DB 8.9", "DB 7.2", "DB 6.3", "DB 8.3"],
        "R2900": ["DB 6.3", "DB 7.2", "DB 8.3", "DB 8.9"],
        "R2900XE": ["DB 7.4", "DB 8.6", "DB 9.2", "DB 9.8"],
        "R3000H": ["DB 10.5", "DB 8.9", "DB 9.5"]
    },
    "Sandvik LHD models": {
        "SANDVIK LH517i": ["DB 7", "DB 7.6", "DB 8.6", "DB 9.1", "DB 8.4"],
        "SANDVIK LH621i": ["DB 8.0", "DB 9.0", "DB 10.7", "DB 11.2"],
        "SANDVIK LH515i": ["DB 6.3", "DB 6.8", "DB 7.5"],
        "SANDVIK LH514": ["DB 6.2", "DB 7", "DB 5.4"],
        "Toro™ LH625iE": ["DB 10"],
        "Sandvik LH514E": ["DB 4.6", "DB 5", "DB 5.4", "DB 6.2", "DB 7"],
        "Toro™ LH514BE": ["DB 4.6", "DB 5", "DB 5.4", "DB 6.2", "DB 7", "DB 7.5"],
        "Sandvik LH409E": ["DB 3.8", "DB 4.3", "DB 4.6"]
    },
    "Epiroc LHD models": {
        "Epiroc ST14 SG": ["DB 4.7", "DB 5", "DB 5.4", "DB 5.8", "DB 6.4", "DB 7.0", "DB 7.8"],
        "Epiroc ST18 SG": ["DB 9.7", "DB 8.8", "DB 7.9", "DB 7.3", "DB 6.7", "DB 6.3"],
        "Epiroc ST14": ["DB 4.7", "DB 5", "DB 5.4", "DB 5.8", "DB 6.4", "DB 7.0", "DB 7.8"],
        "Epiroc ST18 S": ["DB 9.7", "DB 8.8", "DB 7.9", "DB 7.3", "DB 6.7", "DB 6.3"]
    },
    "Komatsu LHD models": {
        "WX18H": ["DB 8.2", "DB 9.2", "DB 10", "DB 11.2"],
        "WX22H": ["DB 10", "DB 11", "DB 12.2", "DB 13.8"]
    }
}

payloads = {
    "R1300G": 6800,
    "R1600H": 10200,
    "R1700": 15000,
    "R1700XE": 15000,
    "R1700G": 12500,
    "R2900G": 17200,
    "R2900": 17200,
    "R2900XE": 18500,
    "R3000H": 20000,
    "SANDVIK LH517i": 17200,
    "SANDVIK LH621i": 21000,
    "SANDVIK LH515i": 15000,
    "SANDVIK LH514": 14000,
    "Toro™ LH625iE": 25000,
    "Sandvik LH514E": 14000,
    "Toro™ LH514BE": 14000,
    "Sandvik LH409E": 9600,
    "Epiroc ST14 SG": 14000,
    "Epiroc ST18 SG": 17500,
    "Epiroc ST14": 14000,
    "Epiroc ST18 S": 17500,
    "WX18H": 18000,
    "WX22H": 22000
}


#Widget Configuration Functions:===========================================================
def set_widget_bg_color(widget, bg_color, fg_color="black"):
    widget_class = widget.winfo_class()
    
    if widget_class == "Label":
        widget.config(bg=bg_color, fg=fg_color)  # Set the foreground color to fg_color
    elif widget_class == "Frame" or widget_class == "Toplevel":
        widget.config(bg=bg_color)
    elif widget_class == "Text":
        widget.config(bg=bg_color, fg=fg_color, insertbackground=fg_color)  # Set the foreground color to fg_color
    # Add more widgets here as needed

    # Recursively apply to children
    for child in widget.winfo_children():
        set_widget_bg_color(child, bg_color, fg_color)


def on_group_selected(column):
    selected_group = group_vars[column].get()
    model_dropdowns[column]['values'] = list(models_data[selected_group].keys())
    model_vars[column].set("Select Model")
    buckets_dropdowns[column]['values'] = []
    update_all_timings(column)  # Update timings first


def on_model_selected(column):
    selected_group = group_vars[column].get()
    selected_model = model_vars[column].get()
    if selected_model != "Select Model":
        buckets_dropdowns[column]['values'] = models_data[selected_group][selected_model]
        payload_labels[column].config(text=f"{payloads.get(selected_model, 'N/A')} kg")
        update_model_travel_times(column)
        update_all_timings(column)



def update_all_timings(col):
    # Call the functions to update timings for this column
    update_model_travel_times(col)
    calculate_cycle_time(col)

def update_model_travel_times(col):
    raw_distance = travel_distance_entries[col].get()
    load_time_empty = not load_time_entries[col].get().strip()
    dump_time_empty = not dump_time_entries[col].get().strip()
    delay_time_empty = not delay_time_entries[col].get().strip()

    if not raw_distance.strip():
        if load_time_empty and dump_time_empty and delay_time_empty:
            model_travel_time_labels[col].config(text="Input Required")
            flash_red(model_travel_time_labels[col])
        else:
            model_travel_time_labels[col].config(text="")
            # Reset the color to the original color if it was flashed
            model_travel_time_labels[col].config(foreground="black")
    else:
        try:
            travel_distance = float(raw_distance)
            travel_time = calculate_travel_time(travel_distance)
            formatted_travel_time = format_duration(travel_time * 60)
            model_travel_time_labels[col].config(text=formatted_travel_time)
        except ValueError:
            model_travel_time_labels[col].config(text="Invalid Distance")
            flash_red(model_travel_time_labels[col])






def calculate_cycle_time(col):
    try:
        travel_time = calculate_travel_time(float(travel_distance_entries[col].get()))
        load_time = float(load_time_entries[col].get())
        dump_time = float(dump_time_entries[col].get())
        delay_time = float(delay_time_entries[col].get())
        
        # Calculate total cycle time in hours
        cycle_time = travel_time + load_time/60  + dump_time/60 + delay_time/60 
        
        # Convert cycle time from hours to seconds
        seconds_total = cycle_time * 60
        
        # Format the total time into a readable string format
        formatted_cycle_time = format_duration(seconds_total)
        
        cycle_time_labels[col].config(text=formatted_cycle_time)
    except ValueError:
        cycle_time_labels[col].config(text="Input Required")



    





#Main Application Logic:==============================================================================

root = tk.Tk()
root.title("HRV LHD CPT Tool")

# Create a style for the labels
style = ttk.Style()
style.configure('My.TLabel', background=bg_color, foreground='black', font=("Arial", 10))
style.configure('MyBold.TLabel', background=bg_color, foreground='black', font=("Arial", 10, "bold"))



canvas_frame = tk.Frame(root)
canvas_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

canvas = tk.Canvas(canvas_frame,  bg=bg_color)
canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

scrollbar = ttk.Scrollbar(canvas_frame, orient="vertical", command=canvas.yview)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

canvas.configure(yscrollcommand=scrollbar.set)

content_frame = tk.Frame(canvas)
canvas.create_window((0, 0), window=content_frame, anchor="nw")


# Dynamic UI Creation
num_columns = len(models_data) # This line needs to be here, before any access to num_columns
group_vars = []
model_vars = []
model_dropdowns = []
buckets_dropdowns = []
travel_distance_entries = []
calculate_buttons = []
payload_labels = []
model_travel_time_labels = []
load_time_entries = []
dump_time_entries = []
delay_time_entries = []
cycle_time_labels = []
payload_titles = []
raw_distance =[]
travel_distance =[]




for col in range(num_columns):
    
    # Group dropdown
    group_var = tk.StringVar()
    group_var.set(list(models_data.keys())[col])
    group_vars.append(group_var)
    
    group_dropdown = ttk.Combobox(content_frame, textvariable=group_var, values=list(models_data.keys()), width=21)
    group_dropdown.bind("<<ComboboxSelected>>", lambda event, col=col: on_group_selected(col))
    group_dropdown.grid(row=0, column=col, padx=10, pady=10)
    
    # Model dropdown
    model_var = tk.StringVar()
    model_var.set("Select Model")
    model_vars.append(model_var)
    
    model_dropdown = ttk.Combobox(content_frame, textvariable=model_var, values=[], width=18)
    model_dropdown.bind("<<ComboboxSelected>>", lambda event, col=col: on_model_selected(col))
    model_dropdown.grid(row=1, column=col, padx=10, pady=10)
    model_dropdowns.append(model_dropdown)
    
    # Buckets dropdown
    buckets_var = tk.StringVar()
    buckets_var.set("Select Bucket")
    buckets_dropdown = ttk.Combobox(content_frame, textvariable=buckets_var, values=[], width=8)
    buckets_dropdown.grid(row=2, column=col, padx=10, pady=10)
    buckets_dropdowns.append(buckets_dropdown)

    # Rated Payload title
    payload_title = ttk.Label(content_frame, text="Rated Payload (kg)", font=("Arial", 10, "bold"), style='MyBold.TLabel')
    payload_title.grid(row=3, column=col, padx=10, pady=5)
    payload_titles.append(payload_title)

    # Rated Payload for the model
    payload_label = ttk.Label(content_frame, text="N/A", font=("Arial", 10), style='MyBold.TLabel')
    payload_label.grid(row=4, column=col, padx=10, pady=5)
    payload_labels.append(payload_label)

    # Travel Distance Entry
    travel_distance_var_col = tk.StringVar()
    travel_distance_entry_col = tk.Entry(content_frame, textvariable=travel_distance_var_col, justify=tk.CENTER, width=8)
    travel_distance_entry_col.grid(row=5, column=col, padx=10, pady=5)
    travel_distance_entries.append(travel_distance_entry_col)

    # Calculate button for the column
    calculate_button_col = tk.Button(content_frame, text="Calculate", command=lambda col=col: update_all_timings(col))
    calculate_button_col.grid(row=20, column=col, padx=10, pady=10)
    calculate_buttons.append(calculate_button_col)


    # Adding title for Travel Time
    travel_time_title = ttk.Label(content_frame, text="Travel Time (hh:mm:ss)", font=("Arial", 10, "bold"), style='MyBold.TLabel')
    travel_time_title.grid(row=7, column=col, padx=10, pady=5)

    # Travel Time label for the model
    travel_time_label = ttk.Label(content_frame, text="N/A", font=("Arial", 10,"bold"), style='MyBold.TLabel')
    travel_time_label.grid(row=8, column=col, padx=10, pady=5)
    model_travel_time_labels.append(travel_time_label)

    # Load Time Entry
    load_time_var_col = tk.StringVar()
    load_time_label = ttk.Label(content_frame, text="Load Time (seconds)", font=("Arial", 10, "bold"), style='MyBold.TLabel')
    load_time_label.grid(row=9, column=col, padx=10, pady=5)
    load_time_entry = tk.Entry(content_frame, textvariable=load_time_var_col, justify=tk.CENTER, width=8)
    load_time_entry.grid(row=10, column=col, padx=10, pady=5)
    load_time_entries.append(load_time_entry)

    # Dump Time Entry
    dump_time_var_col = tk.StringVar()
    dump_time_label = ttk.Label(content_frame, text="Dump Time (seconds)", font=("Arial", 10, "bold"), style='MyBold.TLabel')
    dump_time_label.grid(row=11, column=col, padx=10, pady=5)
    dump_time_entry = tk.Entry(content_frame, textvariable=dump_time_var_col, justify=tk.CENTER, width=8)
    dump_time_entry.grid(row=12, column=col, padx=10, pady=5)
    dump_time_entries.append(dump_time_entry)

    # Delay Time Entry
    delay_time_var_col = tk.StringVar()
    delay_time_label = ttk.Label(content_frame, text="Delay Time (seconds)", font=("Arial", 10, "bold"), style='MyBold.TLabel')
    delay_time_label.grid(row=13, column=col, padx=10, pady=5)
    delay_time_entry = tk.Entry(content_frame, textvariable=delay_time_var_col, justify=tk.CENTER, width=8)
    delay_time_entry.grid(row=14, column=col, padx=10, pady=5)
    delay_time_entries.append(delay_time_entry)

    # Cycle Time display
    cycle_time_title = ttk.Label(content_frame, text="Cycle Time (hh:mm:ss)", font=("Arial", 10, "bold"), style='MyBold.TLabel')
    cycle_time_title.grid(row=15, column=col, padx=10, pady=5)

    cycle_time_label = ttk.Label(content_frame, text="", font=("Arial", 10, "bold"), style='MyBold.TLabel')
    cycle_time_label.grid(row=16, column=col, padx=10, pady=5)
    cycle_time_labels.append(cycle_time_label)




# Update initial options
for col in range(num_columns):
    on_group_selected(col)
    on_model_selected(col)
    group_vars[col].set(list(models_data.keys())[col])
    model_vars[col].set(list(models_data[list(models_data.keys())[col]].keys())[0])
    buckets_dropdowns[col].set(models_data[list(models_data.keys())[col]][list(models_data[list(models_data.keys())[col]].keys())[0]][0])



# Configure scroll
def on_frame_configure(event):
    canvas.configure(scrollregion=canvas.bbox("all"))

content_frame.bind("<Configure>", on_frame_configure)

# Set widget background colors
set_widget_bg_color(root, bg_color)

for dropdown in model_dropdowns + buckets_dropdowns:
    dropdown['style'] = 'TCombobox'
    dropdown['justify'] = 'center'

# Event Callbacks============================================================================================

def on_group_selected(column):
    selected_group = group_vars[column].get()
    model_dropdowns[column]['values'] = list(models_data[selected_group].keys())
    model_vars[column].set("Select Model")
    buckets_dropdowns[column]['values'] = []


def on_model_selected(column):
    selected_group = group_vars[column].get()
    selected_model = model_vars[column].get()
    if selected_model != "Select Model":
        buckets_dropdowns[column]['values'] = models_data[selected_group][selected_model]
        payload_labels[column].config(text=f"{payloads.get(selected_model, 'N/A')} kg")
        update_model_travel_times(column)



    
    # If you've successfully retrieved the travel distance, continue processing
    travel_time = calculate_travel_time(travel_distance)
    formatted_travel_time = format_duration(travel_time * 60)  # Convert hours to minutes
    model_travel_time_labels[col].config(text=formatted_travel_time)



def update_all_timings(col):
    # Call the functions to update timings for this column
    update_model_travel_times(col)
    calculate_cycle_time(col)
    update_plot()

canvas_frame = tk.Frame(root)
canvas_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# Update the plot initially
update_plot()

# RUN MAIN LOOP
root.mainloop()
deanhystad write Aug-23-2023, 12:33 PM:
Please post code, output and errors between their respective tags. Refer to BBCode help topic on how to post. Use the "Preview Post" button to make sure the code is presented as you expect before hitting the "Post Reply/Thread" button.
Reply


Messages In This Thread
Plot function - by Sedos101 - Aug-23-2023, 09:17 AM
RE: Plot function - by deanhystad - Aug-23-2023, 01:42 PM
RE: Plot function - by Sedos101 - Aug-23-2023, 01:51 PM
RE: Plot function - by deanhystad - Aug-23-2023, 02:53 PM

Possibly Related Threads…
Thread Author Replies Views Last Post
  How to draw the Probability Density Function (PDF) plot regardless of sampe size? amylopectin 3 3,769 Mar-02-2022, 09:34 PM
Last Post: Larz60+
  How to plot intraday data of several days in one plot mistermister 3 3,021 Dec-15-2020, 07:43 PM
Last Post: deanhystad
  How to plot vertically stacked plot with same x-axis and SriMekala 0 1,991 Jun-12-2019, 03:31 PM
Last Post: SriMekala

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020