From b3edafa796de6f2c2ad6693a15ded2e75b833ad3 Mon Sep 17 00:00:00 2001 From: Markus Koller Date: Fri, 3 Mar 2023 10:33:07 +0100 Subject: [PATCH] Plotting only part of csv if csv has more than 1000 plot points --- src/csv_threading.py | 46 +++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/csv_threading.py b/src/csv_threading.py index 0dc7552..07ef2a7 100644 --- a/src/csv_threading.py +++ b/src/csv_threading.py @@ -61,16 +61,21 @@ class ExecCSVThread(Thread): return self._stop_event.is_set() def execute_sequence(self, array, delay, parent, controller): + # Initialize plot + ui_print("Initializing plots...") + figure, avx_lines = display_plot(parent) + # main execution method of the class # runs through array with times and desired fields and commands test bench accordingly # array format: [time (s), xField (T), yField (T), zField (T)] + ui_print("Initializing cage...") self.cage_dev.idle() # sets outputs on PSUs to 0 and Arduino pins to LOW before starting t_zero = time.time() # set reference time for start of run # Check if everything is properly connected: - all_connected = (parent.xy_override.get() or g.CAGE_DEVICE.psu1 is not None) and\ - (parent.z_override.get() or g.CAGE_DEVICE.psu2 is not None) and\ + all_connected = (parent.xy_override.get() or g.CAGE_DEVICE.psu1 is not None) and \ + (parent.z_override.get() or g.CAGE_DEVICE.psu2 is not None) and \ (parent.arduino_override.get() or g.CAGE_DEVICE.arduino is not None) compensate_field = parent.compensated_field_var.get() @@ -80,9 +85,7 @@ class ExecCSVThread(Thread): messagebox.showwarning("Device Error!", "Required devices are not present, sequence aborted.") return - # Initialize plot - figure, avx_lines = display_plot(parent) - + ui_print("Starting csv replay...") i = 0 # index of the current array row while i < len(array): if self.stopped or g.exit_flag: @@ -113,10 +116,14 @@ class ExecCSVThread(Thread): # Update figure try: - for j in range(4): - avx_lines[j].set_data([t, t], [0, 1]) - # print("The next line might crash the programm, outcomment if necessary") - parent.plot_canvas.draw() # equivalent to matplotlib.show() + if abs(t - target_t) < 0.2: + for j in range(4): + avx_lines[j].set_data([t, t], [0, 1]) + # print("The next line might crash the programm, outcomment if necessary") + parent.plot_canvas.draw() # equivalent to matplotlib.show() + else: + ui_print("Update rate of plot slows down field generation and is thus skipped.") + except DeviceAccessError as e: ui_print("Failed to update figure: ", e) @@ -125,7 +132,6 @@ class ExecCSVThread(Thread): elif t <= target_t - delay - 0.02: # is there enough time to sleep before the next row? time.sleep(delay) # sleep to give other threads time to run - ui_print("Sequence executed, powering down channels.") @@ -152,7 +158,7 @@ def check_array_ok(array): data_point = array[row_idx, i + 1] # extract data for this axis from array if data_point > max_val or data_point < min_val: # Out of bounds - warnings.append({'row': row_idx+1, 'axis': g.AXIS_NAMES[i]}) + warnings.append({'row': row_idx + 1, 'axis': g.AXIS_NAMES[i]}) # show warning pop-up if values are exceeding limits nr_warnings = len(warnings) @@ -194,7 +200,7 @@ def display_plot(parent): # create plot of fixed size (pixels) from array axes[2].axvline(x=0, color="r"), axes[3].axvline(x=0, color="r")] # Show new plot parent.plot_canvas = FigureCanvasTkAgg(figure, parent.plot_frame) # create canvas to draw figure on - #print("The next line might crash the programm, outcomment if necessary") + # print("The next line might crash the programm, outcomment if necessary") parent.plot_canvas.draw() # equivalent to matplotlib.show() parent.plot_canvas.get_tk_widget().grid(row=0, column=0, sticky="nesw") # place canvas in the UI @@ -204,8 +210,8 @@ def display_plot(parent): # create plot of fixed size (pixels) from array def plot_field_sequence(array, width, height): # create plot of fixed size (pixels) from array # ToDo (optional): polar plots, plots of angle... fig_dpi = 100 # set figure resolution (dots per inch) - px = 1/fig_dpi # get pixel to inch size conversion - figure = plt.Figure(figsize=(width*px, height*px), dpi=fig_dpi) # create figure with correct size + px = 1 / fig_dpi # get pixel to inch size conversion + figure = plt.Figure(figsize=(width * px, height * px), dpi=fig_dpi) # create figure with correct size # noinspection PyTypeChecker,SpellCheckingInspection axes = figure.subplots(4, sharex=True, sharey=False, gridspec_kw={'hspace': 0.4}) # make subplots with shared axes @@ -215,8 +221,18 @@ def plot_field_sequence(array, width, height): # create plot of fixed size (pix # modify data to show instantaneous jumps in field to reflect test bench operation new_array = np.array([[0, 0, 0, 0, 0]], dtype=float) # initialize modified array, zeros to show start from no field + length = len(array[:, 0]) + max_length = 1000 + if length > max_length: + n = round(length/max_length) # plot every n-th element + ui_print("Array contains {:d} elements more than the maximum amount of {:d}. " + "To improve display only every {:d} element is plotted!" + .format(length, max_length, n)) + else: + n = 1 # plot every element + last_values = [0, 0, 0, 0] # [x,y,z, rr] field values / rot rate from last data point (zero here) - for row in array[:, 0:5]: # go through each row in the original array + for row in array[::n, 0:5]: # go through each row in the original array # create extra datapoint at current timestamp, with field values from last to create a "step" in the plot: new_array = np.append(new_array, [[row[0], *last_values]], axis=0) new_array = np.append(new_array, [row], axis=0) # add actual datapoint for current timestamp