mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 03:31:50 +02:00
refactor: improve plotting behaviour from history
This commit is contained in:
@ -1098,17 +1098,20 @@ class Waveform(PlotBase):
|
|||||||
if len(np.shape(device_data)) > 1:
|
if len(np.shape(device_data)) > 1:
|
||||||
device_data = device_data[-1, :]
|
device_data = device_data[-1, :]
|
||||||
|
|
||||||
x_data = self._get_x_data(device_name, device_entry)
|
if device_data is None:
|
||||||
|
logger.warning(f"Async data for curve {curve.name()} is None.")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Async curves only support plotting vs index or other device
|
||||||
|
if self.x_axis_mode["name"] in ["timestamp", "index", "auto"]:
|
||||||
|
device_data_x = np.linspace(0, len(device_data) - 1, len(device_data))
|
||||||
|
else:
|
||||||
|
# Fetch data from signal instead
|
||||||
|
device_data_x = self._get_x_data(device_name, device_entry)
|
||||||
|
|
||||||
|
self._auto_adjust_async_curve_settings(curve, len(device_data))
|
||||||
|
curve.setData(device_data_x, device_data)
|
||||||
|
|
||||||
# If there's actual data, set it
|
|
||||||
if device_data is not None:
|
|
||||||
self._auto_adjust_async_curve_settings(curve, len(device_data))
|
|
||||||
if x_data is not None or self.x_axis_mode["name"] == "timestamp":
|
|
||||||
curve.setData(x_data, device_data)
|
|
||||||
else:
|
|
||||||
curve.setData(
|
|
||||||
np.linspace(0, len(device_data) - 1, len(device_data)), device_data
|
|
||||||
)
|
|
||||||
self.request_dap_update.emit()
|
self.request_dap_update.emit()
|
||||||
|
|
||||||
def _setup_async_curve(self, curve: Curve):
|
def _setup_async_curve(self, curve: Curve):
|
||||||
@ -1137,69 +1140,72 @@ class Waveform(PlotBase):
|
|||||||
@SafeSlot(dict, dict)
|
@SafeSlot(dict, dict)
|
||||||
def on_async_readback(self, msg, metadata):
|
def on_async_readback(self, msg, metadata):
|
||||||
"""
|
"""
|
||||||
Get async data readback.
|
Get async data readback. This code needs to be fast, therefor we try
|
||||||
|
to reduce the number of copies in between cycles. Be careful when refactoring
|
||||||
|
this part as it will affect the performance of the async readback.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
We create data_plot_x and data_plot_y and modify them within this function
|
||||||
|
to avoid creating new arrays. This is important for performance.
|
||||||
|
We adjust the variables based on instruction type.
|
||||||
|
- add: Add the new data to the existing data.
|
||||||
|
- add_slice: Add the new data to the existing data and set the slice index.
|
||||||
|
- replace: Replace the existing data with the new data.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
msg(dict): Message with the async data.
|
msg(dict): Message with the async data.
|
||||||
metadata(dict): Metadata of the message.
|
metadata(dict): Metadata of the message.
|
||||||
"""
|
"""
|
||||||
instruction = metadata.get("async_update", {}).get("type")
|
instruction = metadata.get("async_update", {}).get("type")
|
||||||
|
if instruction not in ["add", "add_slice", "replace"]:
|
||||||
|
logger.warning(f"Invalid async update instruction: {instruction}")
|
||||||
|
return
|
||||||
max_shape = metadata.get("async_update", {}).get("max_shape", [])
|
max_shape = metadata.get("async_update", {}).get("max_shape", [])
|
||||||
|
plot_mode = self.x_axis_mode["name"]
|
||||||
for curve in self._async_curves:
|
for curve in self._async_curves:
|
||||||
new_data = None
|
x_data = None # Reset x_data
|
||||||
y_data = None
|
# Get the curve data
|
||||||
x_data = None
|
|
||||||
x_name = self.x_axis_mode["name"]
|
|
||||||
async_data = msg["signals"].get(curve.config.signal.entry, None)
|
async_data = msg["signals"].get(curve.config.signal.entry, None)
|
||||||
if async_data is None:
|
if async_data is None:
|
||||||
continue
|
continue
|
||||||
data_plot = async_data["value"]
|
# y-data
|
||||||
|
data_plot_y = async_data["value"]
|
||||||
|
if data_plot_y is None:
|
||||||
|
logger.warning(f"Async data for curve {curve.name()} is None.")
|
||||||
|
continue
|
||||||
# Add
|
# Add
|
||||||
if instruction == "add":
|
if instruction == "add":
|
||||||
if len(max_shape) > 1:
|
if len(max_shape) > 1:
|
||||||
if len(data_plot.shape) > 1:
|
# Ensure that data_plot_y is numpy array, this avoids copying if data_plot_y is already a numpy array
|
||||||
data_plot = data_plot[-1, :]
|
data_plot_y = np.asarray(data_plot_y)
|
||||||
|
if len(data_plot_y.shape) > 1:
|
||||||
|
data_plot_y = data_plot_y[-1, :]
|
||||||
else:
|
else:
|
||||||
x_data, y_data = curve.get_data()
|
x_data, y_data = curve.get_data()
|
||||||
|
if y_data is not None:
|
||||||
if y_data is not None:
|
data_plot_y = np.hstack((y_data, data_plot_y))
|
||||||
new_data = np.hstack((y_data, data_plot)) # TODO check performance
|
|
||||||
else:
|
|
||||||
new_data = data_plot
|
|
||||||
if x_name == "timestamp":
|
|
||||||
if x_data is not None:
|
|
||||||
x_data = np.hstack((x_data, async_data["timestamp"]))
|
|
||||||
else:
|
|
||||||
x_data = async_data["timestamp"]
|
|
||||||
# FIXME x axis wrong if timestamp switched during scan
|
|
||||||
# Add slice
|
# Add slice
|
||||||
elif instruction == "add_slice":
|
if instruction == "add_slice":
|
||||||
current_slice_id = metadata.get("async_update", {}).get("index")
|
current_slice_id = metadata.get("async_update", {}).get("index")
|
||||||
data_plot = async_data["value"]
|
|
||||||
if current_slice_id != curve.slice_index:
|
if current_slice_id != curve.slice_index:
|
||||||
curve.slice_index = current_slice_id
|
curve.slice_index = current_slice_id
|
||||||
else:
|
else:
|
||||||
x_data, y_data = curve.get_data()
|
x_data, y_data = curve.get_data()
|
||||||
if y_data is not None:
|
if y_data is not None:
|
||||||
new_data = np.hstack((y_data, data_plot))
|
data_plot_y = np.hstack((y_data, data_plot_y))
|
||||||
else:
|
|
||||||
new_data = data_plot
|
|
||||||
# Replace
|
|
||||||
elif instruction == "replace":
|
|
||||||
if x_name == "timestamp":
|
|
||||||
x_data = async_data["timestamp"]
|
|
||||||
new_data = data_plot
|
|
||||||
|
|
||||||
# If update is not add, add_slice or replace, continue.
|
# Replace is trivial, no need to modify data_plot_y
|
||||||
if new_data is None:
|
|
||||||
continue
|
# Get the x data if 'timestamp' is selected, otherwise compute it
|
||||||
# Hide symbol, activate downsampling if data >1000
|
data_plot_x = async_data["timestamp"]
|
||||||
self._auto_adjust_async_curve_settings(curve, len(new_data))
|
if plot_mode == "timestamp" and instruction != "add_slice":
|
||||||
# Set data on the curve
|
if data_plot_x is not None and x_data is not None:
|
||||||
if x_name == "timestamp" and instruction != "add_slice":
|
data_plot_x = np.hstack((x_data, data_plot_x))
|
||||||
curve.setData(x_data, new_data)
|
|
||||||
else:
|
else:
|
||||||
curve.setData(np.linspace(0, len(new_data) - 1, len(new_data)), new_data)
|
data_plot_x = np.linspace(0, len(data_plot_y) - 1, len(data_plot_y))
|
||||||
|
# Set the x data
|
||||||
|
self._auto_adjust_async_curve_settings(curve, len(data_plot_y))
|
||||||
|
curve.setData(data_plot_x, data_plot_y)
|
||||||
|
|
||||||
self.request_dap_update.emit()
|
self.request_dap_update.emit()
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user