|
@@ -0,0 +1,134 @@
|
|
|
+import customtkinter as ctk
|
|
|
+import pandas as pd
|
|
|
+import matplotlib.pyplot as plt
|
|
|
+import numpy as np
|
|
|
+from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
|
|
|
+from tkinter import filedialog
|
|
|
+
|
|
|
+# Function to load data from file
|
|
|
+def load_data():
|
|
|
+ filename = filedialog.askopenfilename(title="Select CSV file", filetypes=(("CSV files", "*.csv"), ("All files", "*.*")))
|
|
|
+ return pd.read_csv(filename)
|
|
|
+
|
|
|
+# Function to update data
|
|
|
+def update_data():
|
|
|
+ global data
|
|
|
+ data = load_data()
|
|
|
+ update_plot(start_slider.get(), end_slider.get())
|
|
|
+
|
|
|
+# Function to update plot based on slider values
|
|
|
+def update_plot(start_time, end_time):
|
|
|
+ filtered_data = data[(data["Timestamp"] >= start_time) & (data["Timestamp"] <= end_time)]
|
|
|
+ ax1.clear()
|
|
|
+ ax1.plot(filtered_data["Timestamp"], filtered_data["Value"])
|
|
|
+ ax1.set_title("Time Domain")
|
|
|
+ ax1.set_xlabel("Timestamp")
|
|
|
+ ax1.set_ylabel("Value")
|
|
|
+
|
|
|
+ # Remove DC offset
|
|
|
+ data_without_dc = filtered_data["Value"] - filtered_data["Value"].mean()
|
|
|
+
|
|
|
+ # Perform Fourier analysis
|
|
|
+ fft_values = np.fft.fft(data_without_dc)
|
|
|
+ frequencies = np.fft.fftfreq(len(filtered_data), d=1 / sampling_rate)
|
|
|
+ amplitudes = np.abs(fft_values)
|
|
|
+
|
|
|
+ # Consider only positive frequencies
|
|
|
+ positive_frequencies = frequencies[:len(frequencies)//2]
|
|
|
+ positive_amplitudes = amplitudes[:len(frequencies)//2]
|
|
|
+
|
|
|
+ ax2.clear()
|
|
|
+ ax2.plot(positive_frequencies, positive_amplitudes)
|
|
|
+ ax2.set_title("Frequency Domain")
|
|
|
+ ax2.set_xlabel("Frequency (Hz)")
|
|
|
+ ax2.set_ylabel("Amplitude")
|
|
|
+
|
|
|
+ canvas.draw()
|
|
|
+
|
|
|
+# Create the main CustomTkinter window
|
|
|
+root = ctk.CTk()
|
|
|
+root.title("CSV Plot with Two Sliders")
|
|
|
+
|
|
|
+# Set appearance mode (optional)
|
|
|
+ctk.set_appearance_mode("dark") # Choose between "dark", "light", or "system"
|
|
|
+
|
|
|
+# Create matplotlib figure and axes
|
|
|
+fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 6))
|
|
|
+canvas = FigureCanvasTkAgg(fig, master=root)
|
|
|
+canvas.get_tk_widget().pack(side=ctk.LEFT, fill=ctk.BOTH, expand=True)
|
|
|
+
|
|
|
+# Function to initialize the plot
|
|
|
+def init_plot():
|
|
|
+ global data
|
|
|
+ global sampling_rate
|
|
|
+ data = load_data()
|
|
|
+
|
|
|
+ # Read the CSV file and extract timestamps
|
|
|
+ timestamps = data["Timestamp"].tolist()
|
|
|
+
|
|
|
+ # Calculate time differences
|
|
|
+ time_diffs = [timestamps[i + 1] - timestamps[i] for i in range(len(timestamps) - 1)]
|
|
|
+
|
|
|
+ # Calculate average time difference
|
|
|
+ average_time_diff = sum(time_diffs) / len(time_diffs)
|
|
|
+
|
|
|
+ # Sampling rate is the reciprocal of the average time difference
|
|
|
+ sampling_rate = 1 / average_time_diff
|
|
|
+ print("Sampling rate:", sampling_rate, "Hz")
|
|
|
+
|
|
|
+ # Load only the last 10000 data points
|
|
|
+ data = data.tail(10000)
|
|
|
+
|
|
|
+ # Plot the initial data
|
|
|
+ ax1.plot(data["Timestamp"], data["Value"])
|
|
|
+ ax1.set_title("Time Domain")
|
|
|
+ ax1.set_xlabel("Timestamp")
|
|
|
+ ax1.set_ylabel("Value")
|
|
|
+
|
|
|
+ # Remove DC offset
|
|
|
+ data_without_dc = data["Value"] - data["Value"].mean()
|
|
|
+
|
|
|
+ # Perform Fourier analysis
|
|
|
+ fft_values = np.fft.fft(data_without_dc)
|
|
|
+ frequencies = np.fft.fftfreq(len(data), d=1 / sampling_rate)
|
|
|
+ amplitudes = np.abs(fft_values)
|
|
|
+
|
|
|
+ # Consider only positive frequencies
|
|
|
+ positive_frequencies = frequencies[:len(frequencies)//2]
|
|
|
+ positive_amplitudes = amplitudes[:len(frequencies)//2]
|
|
|
+
|
|
|
+ # Plot frequency spectrum
|
|
|
+ ax2.plot(positive_frequencies, positive_amplitudes)
|
|
|
+ ax2.set_title("Frequency Domain")
|
|
|
+ ax2.set_xlabel("Frequency (Hz)")
|
|
|
+ ax2.set_ylabel("Amplitude")
|
|
|
+
|
|
|
+# Initialize the plot
|
|
|
+init_plot()
|
|
|
+
|
|
|
+# Create sliders
|
|
|
+start_slider = ctk.CTkSlider(master=root, from_=data["Timestamp"].min(), to=data["Timestamp"].max(),
|
|
|
+ command=lambda value: update_plot(value, end_slider.get()))
|
|
|
+start_slider.pack()
|
|
|
+
|
|
|
+end_slider = ctk.CTkSlider(master=root, from_=data["Timestamp"].min(), to=data["Timestamp"].max(),
|
|
|
+ command=lambda value: update_plot(start_slider.get(), value))
|
|
|
+end_slider.pack()
|
|
|
+
|
|
|
+# Create a frame on the right side for displaying relevant information
|
|
|
+info_frame = ctk.CTkFrame(master=root)
|
|
|
+info_frame.pack(side=ctk.RIGHT, fill=ctk.BOTH, expand=True)
|
|
|
+
|
|
|
+# Labels for displaying information
|
|
|
+sampling_rate_label = ctk.CTkLabel(master=info_frame, text=f"Sampling Rate: {sampling_rate} Hz")
|
|
|
+sampling_rate_label.pack()
|
|
|
+
|
|
|
+max_frequency_label = ctk.CTkLabel(master=info_frame, text=f"Max Frequency: {sampling_rate / 2} Hz (Nyquist Frequency)")
|
|
|
+max_frequency_label.pack()
|
|
|
+
|
|
|
+# Button to change data file
|
|
|
+change_file_button = ctk.CTkButton(master=info_frame, text="Change File", command=update_data)
|
|
|
+change_file_button.pack()
|
|
|
+
|
|
|
+# Run the CustomTkinter event loop
|
|
|
+root.mainloop()
|