Aug-23-2023, 09:17 AM
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?
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()