diff --git a/bec_widgets/cli/__init__.py b/bec_widgets/cli/__init__.py index 1a9c609a..421945bc 100644 --- a/bec_widgets/cli/__init__.py +++ b/bec_widgets/cli/__init__.py @@ -1 +1 @@ -from .client import BECDockArea, BECFigure +from .client import * diff --git a/bec_widgets/cli/client.py b/bec_widgets/cli/client.py index ae1b53e5..2b9e7c44 100644 --- a/bec_widgets/cli/client.py +++ b/bec_widgets/cli/client.py @@ -1,10 +1,1261 @@ # This file was automatically generated by generate_cli.py +import enum from typing import Literal, Optional, overload from bec_widgets.cli.client_utils import BECGuiClientMixin, RPCBase, rpc_call +class Widgets(str, enum.Enum): + """ + Enum for the available widgets. + """ + + BECDock = "BECDock" + BECDockArea = "BECDockArea" + BECFigure = "BECFigure" + SpiralProgressBar = "SpiralProgressBar" + WebsiteWidget = "WebsiteWidget" + + +class BECConnector(RPCBase): + @property + @rpc_call + def config_dict(self) -> "dict": + """ + Get the configuration of the widget. + + Returns: + dict: The configuration of the widget. + """ + + @rpc_call + def get_all_rpc(self) -> "dict": + """ + Get all registered RPC objects. + """ + + +class BECCurve(RPCBase): + @rpc_call + def remove(self): + """ + Remove the curve from the plot. + """ + + @property + @rpc_call + def rpc_id(self) -> "str": + """ + Get the RPC ID of the widget. + """ + + @property + @rpc_call + def config_dict(self) -> "dict": + """ + Get the configuration of the widget. + + Returns: + dict: The configuration of the widget. + """ + + @rpc_call + def set(self, **kwargs): + """ + Set the properties of the curve. + + Args: + **kwargs: Keyword arguments for the properties to be set. + + Possible properties: + - color: str + - symbol: str + - symbol_color: str + - symbol_size: int + - pen_width: int + - pen_style: Literal["solid", "dash", "dot", "dashdot"] + """ + + @rpc_call + def set_data(self, x, y): + """ + None + """ + + @rpc_call + def set_color(self, color: "str", symbol_color: "Optional[str]" = None): + """ + Change the color of the curve. + + Args: + color(str): Color of the curve. + symbol_color(str, optional): Color of the symbol. Defaults to None. + """ + + @rpc_call + def set_color_map_z(self, colormap: "str"): + """ + Set the colormap for the scatter plot z gradient. + + Args: + colormap(str): Colormap for the scatter plot. + """ + + @rpc_call + def set_symbol(self, symbol: "str"): + """ + Change the symbol of the curve. + + Args: + symbol(str): Symbol of the curve. + """ + + @rpc_call + def set_symbol_color(self, symbol_color: "str"): + """ + Change the symbol color of the curve. + + Args: + symbol_color(str): Color of the symbol. + """ + + @rpc_call + def set_symbol_size(self, symbol_size: "int"): + """ + Change the symbol size of the curve. + + Args: + symbol_size(int): Size of the symbol. + """ + + @rpc_call + def set_pen_width(self, pen_width: "int"): + """ + Change the pen width of the curve. + + Args: + pen_width(int): Width of the pen. + """ + + @rpc_call + def set_pen_style(self, pen_style: "Literal['solid', 'dash', 'dot', 'dashdot']"): + """ + Change the pen style of the curve. + + Args: + pen_style(Literal["solid", "dash", "dot", "dashdot"]): Style of the pen. + """ + + @rpc_call + def get_data(self) -> "tuple[np.ndarray, np.ndarray]": + """ + Get the data of the curve. + Returns: + tuple[np.ndarray,np.ndarray]: X and Y data of the curve. + """ + + +class BECDock(RPCBase): + @property + @rpc_call + def config_dict(self) -> "dict": + """ + Get the configuration of the widget. + + Returns: + dict: The configuration of the widget. + """ + + @property + @rpc_call + def rpc_id(self) -> "str": + """ + Get the RPC ID of the widget. + """ + + @property + @rpc_call + def widget_list(self) -> "list[BECConnector]": + """ + Get the widgets in the dock. + + Returns: + widgets(list): The widgets in the dock. + """ + + @rpc_call + def show_title_bar(self): + """ + Hide the title bar of the dock. + """ + + @rpc_call + def hide_title_bar(self): + """ + Hide the title bar of the dock. + """ + + @rpc_call + def get_widgets_positions(self) -> "dict": + """ + Get the positions of the widgets in the dock. + + Returns: + dict: The positions of the widgets in the dock as dict -> {(row, col, rowspan, colspan):widget} + """ + + @rpc_call + def set_title(self, title: "str"): + """ + Set the title of the dock. + + Args: + title(str): The title of the dock. + """ + + @rpc_call + def add_widget( + self, + widget: "BECConnector | str", + row=None, + col=0, + rowspan=1, + colspan=1, + shift: "Literal['down', 'up', 'left', 'right']" = "down", + ) -> "BECConnector": + """ + Add a widget to the dock. + + Args: + widget(QWidget): The widget to add. + row(int): The row to add the widget to. If None, the widget will be added to the next available row. + col(int): The column to add the widget to. + rowspan(int): The number of rows the widget should span. + colspan(int): The number of columns the widget should span. + shift(Literal["down", "up", "left", "right"]): The direction to shift the widgets if the position is occupied. + """ + + @rpc_call + def list_eligible_widgets(self) -> "list": + """ + List all widgets that can be added to the dock. + + Returns: + list: The list of eligible widgets. + """ + + @rpc_call + def move_widget(self, widget: "QWidget", new_row: "int", new_col: "int"): + """ + Move a widget to a new position in the layout. + + Args: + widget(QWidget): The widget to move. + new_row(int): The new row to move the widget to. + new_col(int): The new column to move the widget to. + """ + + @rpc_call + def remove_widget(self, widget_rpc_id: "str"): + """ + Remove a widget from the dock. + + Args: + widget_rpc_id(str): The ID of the widget to remove. + """ + + @rpc_call + def remove(self): + """ + Remove the dock from the parent dock area. + """ + + @rpc_call + def attach(self): + """ + Attach the dock to the parent dock area. + """ + + @rpc_call + def detach(self): + """ + Detach the dock from the parent dock area. + """ + + +class BECDockArea(RPCBase, BECGuiClientMixin): + @property + @rpc_call + def config_dict(self) -> "dict": + """ + Get the configuration of the widget. + + Returns: + dict: The configuration of the widget. + """ + + @property + @rpc_call + def panels(self) -> "dict[str, BECDock]": + """ + Get the docks in the dock area. + Returns: + dock_dict(dict): The docks in the dock area. + """ + + @rpc_call + def save_state(self) -> "dict": + """ + Save the state of the dock area. + + Returns: + dict: The state of the dock area. + """ + + @rpc_call + def remove_dock(self, name: "str"): + """ + Remove a dock by name and ensure it is properly closed and cleaned up. + + Args: + name(str): The name of the dock to remove. + """ + + @rpc_call + def restore_state( + self, state: "dict" = None, missing: "Literal['ignore', 'error']" = "ignore", extra="bottom" + ): + """ + Restore the state of the dock area. If no state is provided, the last state is restored. + + Args: + state(dict): The state to restore. + missing(Literal['ignore','error']): What to do if a dock is missing. + extra(str): Extra docks that are in the dockarea but that are not mentioned in state will be added to the bottom of the dockarea, unless otherwise specified by the extra argument. + """ + + @rpc_call + def add_dock( + self, + name: "str" = None, + position: "Literal['bottom', 'top', 'left', 'right', 'above', 'below']" = None, + relative_to: "BECDock | None" = None, + closable: "bool" = False, + floating: "bool" = False, + prefix: "str" = "dock", + widget: "str | QWidget | None" = None, + row: "int" = None, + col: "int" = 0, + rowspan: "int" = 1, + colspan: "int" = 1, + ) -> "BECDock": + """ + Add a dock to the dock area. Dock has QGridLayout as layout manager by default. + + Args: + name(str): The name of the dock to be displayed and for further references. Has to be unique. + position(Literal["bottom", "top", "left", "right", "above", "below"]): The position of the dock. + relative_to(BECDock): The dock to which the new dock should be added relative to. + closable(bool): Whether the dock is closable. + floating(bool): Whether the dock is detached after creating. + prefix(str): The prefix for the dock name if no name is provided. + widget(str|QWidget|None): The widget to be added to the dock. While using RPC, only BEC RPC widgets from RPCWidgetHandler are allowed. + row(int): The row of the added widget. + col(int): The column of the added widget. + rowspan(int): The rowspan of the added widget. + colspan(int): The colspan of the added widget. + + Returns: + BECDock: The created dock. + """ + + @rpc_call + def clear_all(self): + """ + Close all docks and remove all temp areas. + """ + + @rpc_call + def detach_dock(self, dock_name: "str") -> "BECDock": + """ + Undock a dock from the dock area. + + Args: + dock_name(str): The dock to undock. + + Returns: + BECDock: The undocked dock. + """ + + @rpc_call + def attach_all(self): + """ + Return all floating docks to the dock area. + """ + + @rpc_call + def get_all_rpc(self) -> "dict": + """ + Get all registered RPC objects. + """ + + @property + @rpc_call + def temp_areas(self) -> "list": + """ + Get the temporary areas in the dock area. + + Returns: + list: The temporary areas in the dock area. + """ + + +class BECFigure(RPCBase): + @property + @rpc_call + def rpc_id(self) -> "str": + """ + Get the RPC ID of the widget. + """ + + @property + @rpc_call + def config_dict(self) -> "dict": + """ + Get the configuration of the widget. + + Returns: + dict: The configuration of the widget. + """ + + @rpc_call + def axes(self, row: "int", col: "int") -> "BECPlotBase": + """ + Get widget by its coordinates in the figure. + + Args: + row(int): the row coordinate + col(int): the column coordinate + + Returns: + BECPlotBase: the widget at the given coordinates + """ + + @property + @rpc_call + def widgets(self) -> "dict": + """ + All widgets within the figure with gui ids as keys. + Returns: + dict: All widgets within the figure. + """ + + @rpc_call + def add_plot( + self, + x: "list | np.ndarray" = None, + y: "list | np.ndarray" = None, + x_name: "str" = None, + y_name: "str" = None, + z_name: "str" = None, + x_entry: "str" = None, + y_entry: "str" = None, + z_entry: "str" = None, + color: "Optional[str]" = None, + color_map_z: "Optional[str]" = "plasma", + label: "Optional[str]" = None, + validate: "bool" = True, + row: "int" = None, + col: "int" = None, + config=None, + **axis_kwargs, + ) -> "BECWaveform": + """ + Add a Waveform1D plot to the figure at the specified position. + + Args: + x(list | np.ndarray): Custom x data to plot. + y(list | np.ndarray): Custom y data to plot. + x_name(str): The name of the device for the x-axis. + y_name(str): The name of the device for the y-axis. + z_name(str): The name of the device for the z-axis. + x_entry(str): The name of the entry for the x-axis. + y_entry(str): The name of the entry for the y-axis. + z_entry(str): The name of the entry for the z-axis. + color(str): The color of the curve. + color_map_z(str): The color map to use for the z-axis. + label(str): The label of the curve. + validate(bool): If True, validate the device names and entries. + row(int): The row coordinate of the widget in the figure. If not provided, the next empty row will be used. + col(int): The column coordinate of the widget in the figure. If not provided, the next empty column will be used. + config(dict): Additional configuration for the widget. + **axis_kwargs(dict): Additional axis properties to set on the widget after creation. + """ + + @rpc_call + def add_image( + self, + monitor: "str" = None, + color_bar: "Literal['simple', 'full']" = "full", + color_map: "str" = "magma", + data: "np.ndarray" = None, + vrange: "tuple[float, float]" = None, + row: "int" = None, + col: "int" = None, + config=None, + **axis_kwargs, + ) -> "BECImageShow": + """ + Add an image to the figure at the specified position. + + Args: + monitor(str): The name of the monitor to display. + color_bar(Literal["simple","full"]): The type of color bar to display. + color_map(str): The color map to use for the image. + data(np.ndarray): Custom data to display. + vrange(tuple[float, float]): The range of values to display. + row(int): The row coordinate of the widget in the figure. If not provided, the next empty row will be used. + col(int): The column coordinate of the widget in the figure. If not provided, the next empty column will be used. + config(dict): Additional configuration for the widget. + **axis_kwargs: Additional axis properties to set on the widget after creation. + + Returns: + BECImageShow: The image widget. + """ + + @rpc_call + def add_motor_map( + self, + motor_x: "str" = None, + motor_y: "str" = None, + row: "int" = None, + col: "int" = None, + config=None, + **axis_kwargs, + ) -> "BECMotorMap": + """ + Args: + motor_x(str): The name of the motor for the X axis. + motor_y(str): The name of the motor for the Y axis. + row(int): The row coordinate of the widget in the figure. If not provided, the next empty row will be used. + col(int): The column coordinate of the widget in the figure. If not provided, the next empty column will be used. + config(dict): Additional configuration for the widget. + **axis_kwargs: + + Returns: + BECMotorMap: The motor map widget. + """ + + @rpc_call + def plot( + self, + x: "list | np.ndarray | None" = None, + y: "list | np.ndarray | None" = None, + x_name: "str | None" = None, + y_name: "str | None" = None, + z_name: "str | None" = None, + x_entry: "str | None" = None, + y_entry: "str | None" = None, + z_entry: "str | None" = None, + color: "str | None" = None, + color_map_z: "str | None" = "plasma", + label: "str | None" = None, + validate: "bool" = True, + **axis_kwargs, + ) -> "BECWaveform": + """ + Add a 1D waveform plot to the figure. Always access the first waveform widget in the figure. + + Args: + x(list | np.ndarray): Custom x data to plot. + y(list | np.ndarray): Custom y data to plot. + x_name(str): The name of the device for the x-axis. + y_name(str): The name of the device for the y-axis. + z_name(str): The name of the device for the z-axis. + x_entry(str): The name of the entry for the x-axis. + y_entry(str): The name of the entry for the y-axis. + z_entry(str): The name of the entry for the z-axis. + color(str): The color of the curve. + color_map_z(str): The color map to use for the z-axis. + label(str): The label of the curve. + validate(bool): If True, validate the device names and entries. + **axis_kwargs: Additional axis properties to set on the widget after creation. + + Returns: + BECWaveform: The waveform plot widget. + """ + + @rpc_call + def image( + self, + monitor: "str" = None, + color_bar: "Literal['simple', 'full']" = "full", + color_map: "str" = "magma", + data: "np.ndarray" = None, + vrange: "tuple[float, float]" = None, + **axis_kwargs, + ) -> "BECImageShow": + """ + Add an image to the figure. Always access the first image widget in the figure. + + Args: + monitor(str): The name of the monitor to display. + color_bar(Literal["simple","full"]): The type of color bar to display. + color_map(str): The color map to use for the image. + data(np.ndarray): Custom data to display. + vrange(tuple[float, float]): The range of values to display. + **axis_kwargs: Additional axis properties to set on the widget after creation. + + Returns: + BECImageShow: The image widget. + """ + + @rpc_call + def motor_map( + self, motor_x: "str" = None, motor_y: "str" = None, **axis_kwargs + ) -> "BECMotorMap": + """ + Add a motor map to the figure. Always access the first motor map widget in the figure. + + Args: + motor_x(str): The name of the motor for the X axis. + motor_y(str): The name of the motor for the Y axis. + **axis_kwargs: Additional axis properties to set on the widget after creation. + + Returns: + BECMotorMap: The motor map widget. + """ + + @rpc_call + def remove( + self, + row: "int" = None, + col: "int" = None, + widget_id: "str" = None, + coordinates: "tuple[int, int]" = None, + ) -> "None": + """ + Remove a widget from the figure. Can be removed by its unique identifier or by its coordinates. + + Args: + row(int): The row coordinate of the widget to remove. + col(int): The column coordinate of the widget to remove. + widget_id(str): The unique identifier of the widget to remove. + coordinates(tuple[int, int], optional): The coordinates of the widget to remove. + """ + + @rpc_call + def change_layout(self, max_columns=None, max_rows=None): + """ + Reshuffle the layout of the figure to adjust to a new number of max_columns or max_rows. + If both max_columns and max_rows are provided, max_rows is ignored. + + Args: + max_columns (Optional[int]): The new maximum number of columns in the figure. + max_rows (Optional[int]): The new maximum number of rows in the figure. + """ + + @rpc_call + def change_theme(self, theme: "Literal['dark', 'light']") -> "None": + """ + Change the theme of the figure widget. + + Args: + theme(Literal["dark","light"]): The theme to set for the figure widget. + """ + + @rpc_call + def clear_all(self): + """ + Clear all widgets from the figure and reset to default state + """ + + @rpc_call + def get_all_rpc(self) -> "dict": + """ + Get all registered RPC objects. + """ + + @property + @rpc_call + def widget_list(self) -> "list[BECPlotBase]": + """ + Access all widget in BECFigure as a list + Returns: + list[BECPlotBase]: List of all widgets in the figure. + """ + + +class BECImageItem(RPCBase): + @property + @rpc_call + def rpc_id(self) -> "str": + """ + Get the RPC ID of the widget. + """ + + @property + @rpc_call + def config_dict(self) -> "dict": + """ + Get the configuration of the widget. + + Returns: + dict: The configuration of the widget. + """ + + @rpc_call + def set(self, **kwargs): + """ + Set the properties of the image. + + Args: + **kwargs: Keyword arguments for the properties to be set. + + Possible properties: + - downsample + - color_map + - monitor + - opacity + - vrange + - fft + - log + - rot + - transpose + """ + + @rpc_call + def set_fft(self, enable: "bool" = False): + """ + Set the FFT of the image. + + Args: + enable(bool): Whether to perform FFT on the monitor data. + """ + + @rpc_call + def set_log(self, enable: "bool" = False): + """ + Set the log of the image. + + Args: + enable(bool): Whether to perform log on the monitor data. + """ + + @rpc_call + def set_rotation(self, deg_90: "int" = 0): + """ + Set the rotation of the image. + + Args: + deg_90(int): The rotation angle of the monitor data before displaying. + """ + + @rpc_call + def set_transpose(self, enable: "bool" = False): + """ + Set the transpose of the image. + + Args: + enable(bool): Whether to transpose the image. + """ + + @rpc_call + def set_opacity(self, opacity: "float" = 1.0): + """ + Set the opacity of the image. + + Args: + opacity(float): The opacity of the image. + """ + + @rpc_call + def set_autorange(self, autorange: "bool" = False): + """ + Set the autorange of the color bar. + + Args: + autorange(bool): Whether to autorange the color bar. + """ + + @rpc_call + def set_color_map(self, cmap: "str" = "magma"): + """ + Set the color map of the image. + + Args: + cmap(str): The color map of the image. + """ + + @rpc_call + def set_auto_downsample(self, auto: "bool" = True): + """ + Set the auto downsample of the image. + + Args: + auto(bool): Whether to downsample the image. + """ + + @rpc_call + def set_monitor(self, monitor: "str"): + """ + Set the monitor of the image. + + Args: + monitor(str): The name of the monitor. + """ + + @rpc_call + def set_vrange( + self, vmin: "float" = None, vmax: "float" = None, vrange: "tuple[int, int]" = None + ): + """ + Set the range of the color bar. + + Args: + vmin(float): Minimum value of the color bar. + vmax(float): Maximum value of the color bar. + """ + + @rpc_call + def get_data(self) -> "np.ndarray": + """ + Get the data of the image. + Returns: + np.ndarray: The data of the image. + """ + + +class BECImageShow(RPCBase): + @property + @rpc_call + def rpc_id(self) -> "str": + """ + Get the RPC ID of the widget. + """ + + @property + @rpc_call + def config_dict(self) -> "dict": + """ + Get the configuration of the widget. + + Returns: + dict: The configuration of the widget. + """ + + @rpc_call + def add_image_by_config(self, config: "ImageItemConfig | dict") -> "BECImageItem": + """ + Add an image to the widget by configuration. + + Args: + config(ImageItemConfig|dict): The configuration of the image. + + Returns: + BECImageItem: The image object. + """ + + @rpc_call + def get_image_config(self, image_id, dict_output: "bool" = True) -> "ImageItemConfig | dict": + """ + Get the configuration of the image. + + Args: + image_id(str): The ID of the image. + dict_output(bool): Whether to return the configuration as a dictionary. Defaults to True. + + Returns: + ImageItemConfig|dict: The configuration of the image. + """ + + @rpc_call + def get_image_dict(self) -> "dict[str, dict[str, BECImageItem]]": + """ + Get all images. + + Returns: + dict[str, dict[str, BECImageItem]]: The dictionary of images. + """ + + @rpc_call + def add_monitor_image( + self, + monitor: "str", + color_map: "Optional[str]" = "magma", + color_bar: "Optional[Literal['simple', 'full']]" = "simple", + downsample: "Optional[bool]" = True, + opacity: "Optional[float]" = 1.0, + vrange: "Optional[tuple[int, int]]" = None, + **kwargs, + ) -> "BECImageItem": + """ + None + """ + + @rpc_call + def add_custom_image( + self, + name: "str", + data: "Optional[np.ndarray]" = None, + color_map: "Optional[str]" = "magma", + color_bar: "Optional[Literal['simple', 'full']]" = "simple", + downsample: "Optional[bool]" = True, + opacity: "Optional[float]" = 1.0, + vrange: "Optional[tuple[int, int]]" = None, + **kwargs, + ): + """ + None + """ + + @rpc_call + def set_vrange(self, vmin: "float", vmax: "float", name: "str" = None): + """ + Set the range of the color bar. + If name is not specified, then set vrange for all images. + + Args: + vmin(float): Minimum value of the color bar. + vmax(float): Maximum value of the color bar. + name(str): The name of the image. If None, apply to all images. + """ + + @rpc_call + def set_color_map(self, cmap: "str", name: "str" = None): + """ + Set the color map of the image. + If name is not specified, then set color map for all images. + + Args: + cmap(str): The color map of the image. + name(str): The name of the image. If None, apply to all images. + """ + + @rpc_call + def set_autorange(self, enable: "bool" = False, name: "str" = None): + """ + Set the autoscale of the image. + + Args: + enable(bool): Whether to autoscale the color bar. + name(str): The name of the image. If None, apply to all images. + """ + + @rpc_call + def set_monitor(self, monitor: "str", name: "str" = None): + """ + Set the monitor of the image. + If name is not specified, then set monitor for all images. + + Args: + monitor(str): The name of the monitor. + name(str): The name of the image. If None, apply to all images. + """ + + @rpc_call + def set_processing(self, name: "str" = None, **kwargs): + """ + Set the post processing of the image. + If name is not specified, then set post processing for all images. + + Args: + name(str): The name of the image. If None, apply to all images. + **kwargs: Keyword arguments for the properties to be set. + Possible properties: + - fft: bool + - log: bool + - rot: int + - transpose: bool + """ + + @rpc_call + def set_image_properties(self, name: "str" = None, **kwargs): + """ + Set the properties of the image. + + Args: + name(str): The name of the image. If None, apply to all images. + **kwargs: Keyword arguments for the properties to be set. + Possible properties: + - downsample: bool + - color_map: str + - monitor: str + - opacity: float + - vrange: tuple[int,int] + - fft: bool + - log: bool + - rot: int + - transpose: bool + """ + + @rpc_call + def set_fft(self, enable: "bool" = False, name: "str" = None): + """ + Set the FFT of the image. + If name is not specified, then set FFT for all images. + + Args: + enable(bool): Whether to perform FFT on the monitor data. + name(str): The name of the image. If None, apply to all images. + """ + + @rpc_call + def set_log(self, enable: "bool" = False, name: "str" = None): + """ + Set the log of the image. + If name is not specified, then set log for all images. + + Args: + enable(bool): Whether to perform log on the monitor data. + name(str): The name of the image. If None, apply to all images. + """ + + @rpc_call + def set_rotation(self, deg_90: "int" = 0, name: "str" = None): + """ + Set the rotation of the image. + If name is not specified, then set rotation for all images. + + Args: + deg_90(int): The rotation angle of the monitor data before displaying. + name(str): The name of the image. If None, apply to all images. + """ + + @rpc_call + def set_transpose(self, enable: "bool" = False, name: "str" = None): + """ + Set the transpose of the image. + If name is not specified, then set transpose for all images. + + Args: + enable(bool): Whether to transpose the monitor data before displaying. + name(str): The name of the image. If None, apply to all images. + """ + + @rpc_call + def toggle_threading(self, use_threading: "bool"): + """ + Toggle threading for the widgets postprocessing and updating. + + Args: + use_threading(bool): Whether to use threading. + """ + + @rpc_call + def set(self, **kwargs) -> "None": + """ + Set the properties of the plot widget. + + Args: + **kwargs: Keyword arguments for the properties to be set. + + Possible properties: + - title: str + - x_label: str + - y_label: str + - x_scale: Literal["linear", "log"] + - y_scale: Literal["linear", "log"] + - x_lim: tuple + - y_lim: tuple + """ + + @rpc_call + def set_title(self, title: "str"): + """ + Set the title of the plot widget. + + Args: + title(str): Title of the plot widget. + """ + + @rpc_call + def set_x_label(self, label: "str"): + """ + Set the label of the x-axis. + + Args: + label(str): Label of the x-axis. + """ + + @rpc_call + def set_y_label(self, label: "str"): + """ + Set the label of the y-axis. + + Args: + label(str): Label of the y-axis. + """ + + @rpc_call + def set_x_scale(self, scale: "Literal['linear', 'log']" = "linear"): + """ + Set the scale of the x-axis. + + Args: + scale(Literal["linear", "log"]): Scale of the x-axis. + """ + + @rpc_call + def set_y_scale(self, scale: "Literal['linear', 'log']" = "linear"): + """ + Set the scale of the y-axis. + + Args: + scale(Literal["linear", "log"]): Scale of the y-axis. + """ + + @rpc_call + def set_x_lim(self, *args) -> "None": + """ + Set the limits of the x-axis. This method can accept either two separate arguments + for the minimum and maximum x-axis values, or a single tuple containing both limits. + + Usage: + set_x_lim(x_min, x_max) + set_x_lim((x_min, x_max)) + + Args: + *args: A variable number of arguments. Can be two integers (x_min and x_max) + or a single tuple with two integers. + """ + + @rpc_call + def set_y_lim(self, *args) -> "None": + """ + Set the limits of the y-axis. This method can accept either two separate arguments + for the minimum and maximum y-axis values, or a single tuple containing both limits. + + Usage: + set_y_lim(y_min, y_max) + set_y_lim((y_min, y_max)) + + Args: + *args: A variable number of arguments. Can be two integers (y_min and y_max) + or a single tuple with two integers. + """ + + @rpc_call + def set_grid(self, x: "bool" = False, y: "bool" = False): + """ + Set the grid of the plot widget. + + Args: + x(bool): Show grid on the x-axis. + y(bool): Show grid on the y-axis. + """ + + @rpc_call + def lock_aspect_ratio(self, lock): + """ + Lock aspect ratio. + + Args: + lock(bool): True to lock, False to unlock. + """ + + @rpc_call + def remove(self): + """ + Remove the plot widget from the figure. + """ + + @property + @rpc_call + def images(self) -> "list[BECImageItem]": + """ + Get the list of images. + Returns: + list[BECImageItem]: The list of images. + """ + + +class BECMotorMap(RPCBase): + @property + @rpc_call + def config_dict(self) -> "dict": + """ + Get the configuration of the widget. + + Returns: + dict: The configuration of the widget. + """ + + @rpc_call + def change_motors( + self, + motor_x: "str", + motor_y: "str", + motor_x_entry: "str" = None, + motor_y_entry: "str" = None, + validate_bec: "bool" = True, + ) -> "None": + """ + Change the active motors for the plot. + + Args: + motor_x(str): Motor name for the X axis. + motor_y(str): Motor name for the Y axis. + motor_x_entry(str): Motor entry for the X axis. + motor_y_entry(str): Motor entry for the Y axis. + validate_bec(bool, optional): If True, validate the signal with BEC. Defaults to True. + """ + + @rpc_call + def set_max_points(self, max_points: "int") -> "None": + """ + Set the maximum number of points to display. + + Args: + max_points(int): Maximum number of points to display. + """ + + @rpc_call + def set_precision(self, precision: "int") -> "None": + """ + Set the decimal precision of the motor position. + + Args: + precision(int): Decimal precision of the motor position. + """ + + @rpc_call + def set_num_dim_points(self, num_dim_points: "int") -> "None": + """ + Set the number of dim points for the motor map. + + Args: + num_dim_points(int): Number of dim points. + """ + + @rpc_call + def set_background_value(self, background_value: "int") -> "None": + """ + Set the background value of the motor map. + + Args: + background_value(int): Background value of the motor map. + """ + + @rpc_call + def set_scatter_size(self, scatter_size: "int") -> "None": + """ + Set the scatter size of the motor map plot. + + Args: + scatter_size(int): Size of the scatter points. + """ + + @rpc_call + def get_data(self) -> "dict": + """ + Get the data of the motor map. + Returns: + dict: Data of the motor map. + """ + + class BECPlotBase(RPCBase): @property @rpc_call @@ -376,42 +1627,6 @@ class BECWaveform(RPCBase): lock(bool): True to lock, False to unlock. """ - @rpc_call - def plot( - self, - x: "list | np.ndarray | None" = None, - y: "list | np.ndarray | None" = None, - x_name: "str | None" = None, - y_name: "str | None" = None, - z_name: "str | None" = None, - x_entry: "str | None" = None, - y_entry: "str | None" = None, - z_entry: "str | None" = None, - color: "str | None" = None, - color_map_z: "str | None" = "plasma", - label: "str | None" = None, - validate: "bool" = True, - ) -> "BECCurve": - """ - Plot a curve to the plot widget. - Args: - x(list | np.ndarray): Custom x data to plot. - y(list | np.ndarray): Custom y data to plot. - x_name(str): The name of the device for the x-axis. - y_name(str): The name of the device for the y-axis. - z_name(str): The name of the device for the z-axis. - x_entry(str): The name of the entry for the x-axis. - y_entry(str): The name of the entry for the y-axis. - z_entry(str): The name of the entry for the z-axis. - color(str): The color of the curve. - color_map_z(str): The color map to use for the z-axis. - label(str): The label of the curve. - validate(bool): If True, validate the device names and entries. - - Returns: - BECCurve: The curve object. - """ - @rpc_call def remove(self): """ @@ -419,289 +1634,13 @@ class BECWaveform(RPCBase): """ -class BECFigure(RPCBase): - @property - @rpc_call - def rpc_id(self) -> "str": - """ - Get the RPC ID of the widget. - """ - - @property - @rpc_call - def config_dict(self) -> "dict": - """ - Get the configuration of the widget. - - Returns: - dict: The configuration of the widget. - """ - - @rpc_call - def axes(self, row: "int", col: "int") -> "BECPlotBase": - """ - Get widget by its coordinates in the figure. - - Args: - row(int): the row coordinate - col(int): the column coordinate - - Returns: - BECPlotBase: the widget at the given coordinates - """ - - @property - @rpc_call - def widgets(self) -> "dict": - """ - All widgets within the figure with gui ids as keys. - Returns: - dict: All widgets within the figure. - """ - - @rpc_call - def add_plot( - self, - x: "list | np.ndarray" = None, - y: "list | np.ndarray" = None, - x_name: "str" = None, - y_name: "str" = None, - z_name: "str" = None, - x_entry: "str" = None, - y_entry: "str" = None, - z_entry: "str" = None, - color: "Optional[str]" = None, - color_map_z: "Optional[str]" = "plasma", - label: "Optional[str]" = None, - validate: "bool" = True, - row: "int" = None, - col: "int" = None, - config=None, - **axis_kwargs, - ) -> "BECWaveform": - """ - Add a Waveform1D plot to the figure at the specified position. - - Args: - x(list | np.ndarray): Custom x data to plot. - y(list | np.ndarray): Custom y data to plot. - x_name(str): The name of the device for the x-axis. - y_name(str): The name of the device for the y-axis. - z_name(str): The name of the device for the z-axis. - x_entry(str): The name of the entry for the x-axis. - y_entry(str): The name of the entry for the y-axis. - z_entry(str): The name of the entry for the z-axis. - color(str): The color of the curve. - color_map_z(str): The color map to use for the z-axis. - label(str): The label of the curve. - validate(bool): If True, validate the device names and entries. - row(int): The row coordinate of the widget in the figure. If not provided, the next empty row will be used. - col(int): The column coordinate of the widget in the figure. If not provided, the next empty column will be used. - config(dict): Additional configuration for the widget. - **axis_kwargs(dict): Additional axis properties to set on the widget after creation. - """ - - @rpc_call - def add_image( - self, - monitor: "str" = None, - color_bar: "Literal['simple', 'full']" = "full", - color_map: "str" = "magma", - data: "np.ndarray" = None, - vrange: "tuple[float, float]" = None, - row: "int" = None, - col: "int" = None, - config=None, - **axis_kwargs, - ) -> "BECImageShow": - """ - Add an image to the figure at the specified position. - - Args: - monitor(str): The name of the monitor to display. - color_bar(Literal["simple","full"]): The type of color bar to display. - color_map(str): The color map to use for the image. - data(np.ndarray): Custom data to display. - vrange(tuple[float, float]): The range of values to display. - row(int): The row coordinate of the widget in the figure. If not provided, the next empty row will be used. - col(int): The column coordinate of the widget in the figure. If not provided, the next empty column will be used. - config(dict): Additional configuration for the widget. - **axis_kwargs: Additional axis properties to set on the widget after creation. - - Returns: - BECImageShow: The image widget. - """ - - @rpc_call - def add_motor_map( - self, - motor_x: "str" = None, - motor_y: "str" = None, - row: "int" = None, - col: "int" = None, - config=None, - **axis_kwargs, - ) -> "BECMotorMap": - """ - Args: - motor_x(str): The name of the motor for the X axis. - motor_y(str): The name of the motor for the Y axis. - row(int): The row coordinate of the widget in the figure. If not provided, the next empty row will be used. - col(int): The column coordinate of the widget in the figure. If not provided, the next empty column will be used. - config(dict): Additional configuration for the widget. - **axis_kwargs: - - Returns: - BECMotorMap: The motor map widget. - """ - - @rpc_call - def plot( - self, - x: "list | np.ndarray | None" = None, - y: "list | np.ndarray | None" = None, - x_name: "str | None" = None, - y_name: "str | None" = None, - z_name: "str | None" = None, - x_entry: "str | None" = None, - y_entry: "str | None" = None, - z_entry: "str | None" = None, - color: "str | None" = None, - color_map_z: "str | None" = "plasma", - label: "str | None" = None, - validate: "bool" = True, - **axis_kwargs, - ) -> "BECWaveform": - """ - Add a 1D waveform plot to the figure. Always access the first waveform widget in the figure. - - Args: - x(list | np.ndarray): Custom x data to plot. - y(list | np.ndarray): Custom y data to plot. - x_name(str): The name of the device for the x-axis. - y_name(str): The name of the device for the y-axis. - z_name(str): The name of the device for the z-axis. - x_entry(str): The name of the entry for the x-axis. - y_entry(str): The name of the entry for the y-axis. - z_entry(str): The name of the entry for the z-axis. - color(str): The color of the curve. - color_map_z(str): The color map to use for the z-axis. - label(str): The label of the curve. - validate(bool): If True, validate the device names and entries. - **axis_kwargs: Additional axis properties to set on the widget after creation. - - Returns: - BECWaveform: The waveform plot widget. - """ - - @rpc_call - def image( - self, - monitor: "str" = None, - color_bar: "Literal['simple', 'full']" = "full", - color_map: "str" = "magma", - data: "np.ndarray" = None, - vrange: "tuple[float, float]" = None, - **axis_kwargs, - ) -> "BECImageShow": - """ - Add an image to the figure. Always access the first image widget in the figure. - - Args: - monitor(str): The name of the monitor to display. - color_bar(Literal["simple","full"]): The type of color bar to display. - color_map(str): The color map to use for the image. - data(np.ndarray): Custom data to display. - vrange(tuple[float, float]): The range of values to display. - **axis_kwargs: Additional axis properties to set on the widget after creation. - - Returns: - BECImageShow: The image widget. - """ - - @rpc_call - def motor_map( - self, motor_x: "str" = None, motor_y: "str" = None, **axis_kwargs - ) -> "BECMotorMap": - """ - Add a motor map to the figure. Always access the first motor map widget in the figure. - - Args: - motor_x(str): The name of the motor for the X axis. - motor_y(str): The name of the motor for the Y axis. - **axis_kwargs: Additional axis properties to set on the widget after creation. - - Returns: - BECMotorMap: The motor map widget. - """ - - @rpc_call - def remove( - self, - row: "int" = None, - col: "int" = None, - widget_id: "str" = None, - coordinates: "tuple[int, int]" = None, - ) -> "None": - """ - Remove a widget from the figure. Can be removed by its unique identifier or by its coordinates. - - Args: - row(int): The row coordinate of the widget to remove. - col(int): The column coordinate of the widget to remove. - widget_id(str): The unique identifier of the widget to remove. - coordinates(tuple[int, int], optional): The coordinates of the widget to remove. - """ - - @rpc_call - def change_layout(self, max_columns=None, max_rows=None): - """ - Reshuffle the layout of the figure to adjust to a new number of max_columns or max_rows. - If both max_columns and max_rows are provided, max_rows is ignored. - - Args: - max_columns (Optional[int]): The new maximum number of columns in the figure. - max_rows (Optional[int]): The new maximum number of rows in the figure. - """ - - @rpc_call - def change_theme(self, theme: "Literal['dark', 'light']") -> "None": - """ - Change the theme of the figure widget. - - Args: - theme(Literal["dark","light"]): The theme to set for the figure widget. - """ - - @rpc_call - def clear_all(self): - """ - Clear all widgets from the figure and reset to default state - """ - +class Ring(RPCBase): @rpc_call def get_all_rpc(self) -> "dict": """ Get all registered RPC objects. """ - @property - @rpc_call - def widget_list(self) -> "list[BECPlotBase]": - """ - Access all widget in BECFigure as a list - Returns: - list[BECPlotBase]: List of all widgets in the figure. - """ - - -class BECCurve(RPCBase): - @rpc_call - def remove(self): - """ - Remove the curve from the plot. - """ - @property @rpc_call def rpc_id(self) -> "str": @@ -720,940 +1659,78 @@ class BECCurve(RPCBase): """ @rpc_call - def set(self, **kwargs): + def set_value(self, value: "int | float"): """ - Set the properties of the curve. + Set the value for the ring widget Args: - **kwargs: Keyword arguments for the properties to be set. - - Possible properties: - - color: str - - symbol: str - - symbol_color: str - - symbol_size: int - - pen_width: int - - pen_style: Literal["solid", "dash", "dot", "dashdot"] + value(int | float): Value for the ring widget """ @rpc_call - def set_data(self, x, y): + def set_color(self, color: "str | tuple"): """ - None - """ - - @rpc_call - def set_color(self, color: "str", symbol_color: "Optional[str]" = None): - """ - Change the color of the curve. + Set the color for the ring widget Args: - color(str): Color of the curve. - symbol_color(str, optional): Color of the symbol. Defaults to None. + color(str | tuple): Color for the ring widget. Can be HEX code or tuple (R, G, B, A). """ @rpc_call - def set_color_map_z(self, colormap: "str"): + def set_background(self, color: "str | tuple"): """ - Set the colormap for the scatter plot z gradient. + Set the background color for the ring widget Args: - colormap(str): Colormap for the scatter plot. + color(str | tuple): Background color for the ring widget. Can be HEX code or tuple (R, G, B, A). """ @rpc_call - def set_symbol(self, symbol: "str"): + def set_line_width(self, width: "int"): """ - Change the symbol of the curve. + Set the line width for the ring widget Args: - symbol(str): Symbol of the curve. + width(int): Line width for the ring widget """ @rpc_call - def set_symbol_color(self, symbol_color: "str"): + def set_min_max_values(self, min_value: "int | float", max_value: "int | float"): """ - Change the symbol color of the curve. + Set the min and max values for the ring widget. Args: - symbol_color(str): Color of the symbol. + min_value(int | float): Minimum value for the ring widget + max_value(int | float): Maximum value for the ring widget """ @rpc_call - def set_symbol_size(self, symbol_size: "int"): + def set_start_angle(self, start_angle: "int"): """ - Change the symbol size of the curve. + Set the start angle for the ring widget Args: - symbol_size(int): Size of the symbol. + start_angle(int): Start angle for the ring widget in degrees """ @rpc_call - def set_pen_width(self, pen_width: "int"): + def set_update(self, mode: "Literal['manual', 'scan', 'device']", device: "str" = None): """ - Change the pen width of the curve. + Set the update mode for the ring widget. + Modes: + - "manual": Manual update mode, the value is set by the user. + - "scan": Update mode for the scan progress. The value is updated by the current scan progress. + - "device": Update mode for the device readback. The value is updated by the device readback. Take into account that user has to set the device name and limits. Args: - pen_width(int): Width of the pen. + mode(str): Update mode for the ring widget. Can be "manual", "scan" or "device" + device(str): Device name for the device readback mode, only used when mode is "device" """ @rpc_call - def set_pen_style(self, pen_style: "Literal['solid', 'dash', 'dot', 'dashdot']"): + def reset_connection(self): """ - Change the pen style of the curve. - - Args: - pen_style(Literal["solid", "dash", "dot", "dashdot"]): Style of the pen. - """ - - @rpc_call - def get_data(self) -> "tuple[np.ndarray, np.ndarray]": - """ - Get the data of the curve. - Returns: - tuple[np.ndarray,np.ndarray]: X and Y data of the curve. - """ - - -class BECImageShow(RPCBase): - @property - @rpc_call - def rpc_id(self) -> "str": - """ - Get the RPC ID of the widget. - """ - - @property - @rpc_call - def config_dict(self) -> "dict": - """ - Get the configuration of the widget. - - Returns: - dict: The configuration of the widget. - """ - - @rpc_call - def add_image_by_config(self, config: "ImageItemConfig | dict") -> "BECImageItem": - """ - Add an image to the widget by configuration. - - Args: - config(ImageItemConfig|dict): The configuration of the image. - - Returns: - BECImageItem: The image object. - """ - - @rpc_call - def get_image_config(self, image_id, dict_output: "bool" = True) -> "ImageItemConfig | dict": - """ - Get the configuration of the image. - - Args: - image_id(str): The ID of the image. - dict_output(bool): Whether to return the configuration as a dictionary. Defaults to True. - - Returns: - ImageItemConfig|dict: The configuration of the image. - """ - - @rpc_call - def get_image_dict(self) -> "dict[str, dict[str, BECImageItem]]": - """ - Get all images. - - Returns: - dict[str, dict[str, BECImageItem]]: The dictionary of images. - """ - - @rpc_call - def add_monitor_image( - self, - monitor: "str", - color_map: "Optional[str]" = "magma", - color_bar: "Optional[Literal['simple', 'full']]" = "simple", - downsample: "Optional[bool]" = True, - opacity: "Optional[float]" = 1.0, - vrange: "Optional[tuple[int, int]]" = None, - **kwargs, - ) -> "BECImageItem": - """ - None - """ - - @rpc_call - def add_custom_image( - self, - name: "str", - data: "Optional[np.ndarray]" = None, - color_map: "Optional[str]" = "magma", - color_bar: "Optional[Literal['simple', 'full']]" = "simple", - downsample: "Optional[bool]" = True, - opacity: "Optional[float]" = 1.0, - vrange: "Optional[tuple[int, int]]" = None, - **kwargs, - ): - """ - None - """ - - @rpc_call - def set_vrange(self, vmin: "float", vmax: "float", name: "str" = None): - """ - Set the range of the color bar. - If name is not specified, then set vrange for all images. - - Args: - vmin(float): Minimum value of the color bar. - vmax(float): Maximum value of the color bar. - name(str): The name of the image. If None, apply to all images. - """ - - @rpc_call - def set_color_map(self, cmap: "str", name: "str" = None): - """ - Set the color map of the image. - If name is not specified, then set color map for all images. - - Args: - cmap(str): The color map of the image. - name(str): The name of the image. If None, apply to all images. - """ - - @rpc_call - def set_autorange(self, enable: "bool" = False, name: "str" = None): - """ - Set the autoscale of the image. - - Args: - enable(bool): Whether to autoscale the color bar. - name(str): The name of the image. If None, apply to all images. - """ - - @rpc_call - def set_monitor(self, monitor: "str", name: "str" = None): - """ - Set the monitor of the image. - If name is not specified, then set monitor for all images. - - Args: - monitor(str): The name of the monitor. - name(str): The name of the image. If None, apply to all images. - """ - - @rpc_call - def set_processing(self, name: "str" = None, **kwargs): - """ - Set the post processing of the image. - If name is not specified, then set post processing for all images. - - Args: - name(str): The name of the image. If None, apply to all images. - **kwargs: Keyword arguments for the properties to be set. - Possible properties: - - fft: bool - - log: bool - - rot: int - - transpose: bool - """ - - @rpc_call - def set_image_properties(self, name: "str" = None, **kwargs): - """ - Set the properties of the image. - - Args: - name(str): The name of the image. If None, apply to all images. - **kwargs: Keyword arguments for the properties to be set. - Possible properties: - - downsample: bool - - color_map: str - - monitor: str - - opacity: float - - vrange: tuple[int,int] - - fft: bool - - log: bool - - rot: int - - transpose: bool - """ - - @rpc_call - def set_fft(self, enable: "bool" = False, name: "str" = None): - """ - Set the FFT of the image. - If name is not specified, then set FFT for all images. - - Args: - enable(bool): Whether to perform FFT on the monitor data. - name(str): The name of the image. If None, apply to all images. - """ - - @rpc_call - def set_log(self, enable: "bool" = False, name: "str" = None): - """ - Set the log of the image. - If name is not specified, then set log for all images. - - Args: - enable(bool): Whether to perform log on the monitor data. - name(str): The name of the image. If None, apply to all images. - """ - - @rpc_call - def set_rotation(self, deg_90: "int" = 0, name: "str" = None): - """ - Set the rotation of the image. - If name is not specified, then set rotation for all images. - - Args: - deg_90(int): The rotation angle of the monitor data before displaying. - name(str): The name of the image. If None, apply to all images. - """ - - @rpc_call - def set_transpose(self, enable: "bool" = False, name: "str" = None): - """ - Set the transpose of the image. - If name is not specified, then set transpose for all images. - - Args: - enable(bool): Whether to transpose the monitor data before displaying. - name(str): The name of the image. If None, apply to all images. - """ - - @rpc_call - def toggle_threading(self, use_threading: "bool"): - """ - Toggle threading for the widgets postprocessing and updating. - - Args: - use_threading(bool): Whether to use threading. - """ - - @rpc_call - def set(self, **kwargs) -> "None": - """ - Set the properties of the plot widget. - - Args: - **kwargs: Keyword arguments for the properties to be set. - - Possible properties: - - title: str - - x_label: str - - y_label: str - - x_scale: Literal["linear", "log"] - - y_scale: Literal["linear", "log"] - - x_lim: tuple - - y_lim: tuple - """ - - @rpc_call - def set_title(self, title: "str"): - """ - Set the title of the plot widget. - - Args: - title(str): Title of the plot widget. - """ - - @rpc_call - def set_x_label(self, label: "str"): - """ - Set the label of the x-axis. - - Args: - label(str): Label of the x-axis. - """ - - @rpc_call - def set_y_label(self, label: "str"): - """ - Set the label of the y-axis. - - Args: - label(str): Label of the y-axis. - """ - - @rpc_call - def set_x_scale(self, scale: "Literal['linear', 'log']" = "linear"): - """ - Set the scale of the x-axis. - - Args: - scale(Literal["linear", "log"]): Scale of the x-axis. - """ - - @rpc_call - def set_y_scale(self, scale: "Literal['linear', 'log']" = "linear"): - """ - Set the scale of the y-axis. - - Args: - scale(Literal["linear", "log"]): Scale of the y-axis. - """ - - @rpc_call - def set_x_lim(self, *args) -> "None": - """ - Set the limits of the x-axis. This method can accept either two separate arguments - for the minimum and maximum x-axis values, or a single tuple containing both limits. - - Usage: - set_x_lim(x_min, x_max) - set_x_lim((x_min, x_max)) - - Args: - *args: A variable number of arguments. Can be two integers (x_min and x_max) - or a single tuple with two integers. - """ - - @rpc_call - def set_y_lim(self, *args) -> "None": - """ - Set the limits of the y-axis. This method can accept either two separate arguments - for the minimum and maximum y-axis values, or a single tuple containing both limits. - - Usage: - set_y_lim(y_min, y_max) - set_y_lim((y_min, y_max)) - - Args: - *args: A variable number of arguments. Can be two integers (y_min and y_max) - or a single tuple with two integers. - """ - - @rpc_call - def set_grid(self, x: "bool" = False, y: "bool" = False): - """ - Set the grid of the plot widget. - - Args: - x(bool): Show grid on the x-axis. - y(bool): Show grid on the y-axis. - """ - - @rpc_call - def lock_aspect_ratio(self, lock): - """ - Lock aspect ratio. - - Args: - lock(bool): True to lock, False to unlock. - """ - - @rpc_call - def remove(self): - """ - Remove the plot widget from the figure. - """ - - @property - @rpc_call - def images(self) -> "list[BECImageItem]": - """ - Get the list of images. - Returns: - list[BECImageItem]: The list of images. - """ - - -class BECConnector(RPCBase): - @property - @rpc_call - def config_dict(self) -> "dict": - """ - Get the configuration of the widget. - - Returns: - dict: The configuration of the widget. - """ - - @rpc_call - def get_all_rpc(self) -> "dict": - """ - Get all registered RPC objects. - """ - - -class BECImageItem(RPCBase): - @property - @rpc_call - def rpc_id(self) -> "str": - """ - Get the RPC ID of the widget. - """ - - @property - @rpc_call - def config_dict(self) -> "dict": - """ - Get the configuration of the widget. - - Returns: - dict: The configuration of the widget. - """ - - @rpc_call - def set(self, **kwargs): - """ - Set the properties of the image. - - Args: - **kwargs: Keyword arguments for the properties to be set. - - Possible properties: - - downsample - - color_map - - monitor - - opacity - - vrange - - fft - - log - - rot - - transpose - """ - - @rpc_call - def set_fft(self, enable: "bool" = False): - """ - Set the FFT of the image. - - Args: - enable(bool): Whether to perform FFT on the monitor data. - """ - - @rpc_call - def set_log(self, enable: "bool" = False): - """ - Set the log of the image. - - Args: - enable(bool): Whether to perform log on the monitor data. - """ - - @rpc_call - def set_rotation(self, deg_90: "int" = 0): - """ - Set the rotation of the image. - - Args: - deg_90(int): The rotation angle of the monitor data before displaying. - """ - - @rpc_call - def set_transpose(self, enable: "bool" = False): - """ - Set the transpose of the image. - - Args: - enable(bool): Whether to transpose the image. - """ - - @rpc_call - def set_opacity(self, opacity: "float" = 1.0): - """ - Set the opacity of the image. - - Args: - opacity(float): The opacity of the image. - """ - - @rpc_call - def set_autorange(self, autorange: "bool" = False): - """ - Set the autorange of the color bar. - - Args: - autorange(bool): Whether to autorange the color bar. - """ - - @rpc_call - def set_color_map(self, cmap: "str" = "magma"): - """ - Set the color map of the image. - - Args: - cmap(str): The color map of the image. - """ - - @rpc_call - def set_auto_downsample(self, auto: "bool" = True): - """ - Set the auto downsample of the image. - - Args: - auto(bool): Whether to downsample the image. - """ - - @rpc_call - def set_monitor(self, monitor: "str"): - """ - Set the monitor of the image. - - Args: - monitor(str): The name of the monitor. - """ - - @rpc_call - def set_vrange( - self, vmin: "float" = None, vmax: "float" = None, vrange: "tuple[int, int]" = None - ): - """ - Set the range of the color bar. - - Args: - vmin(float): Minimum value of the color bar. - vmax(float): Maximum value of the color bar. - """ - - @rpc_call - def get_data(self) -> "np.ndarray": - """ - Get the data of the image. - Returns: - np.ndarray: The data of the image. - """ - - -class BECMotorMap(RPCBase): - @property - @rpc_call - def config_dict(self) -> "dict": - """ - Get the configuration of the widget. - - Returns: - dict: The configuration of the widget. - """ - - @rpc_call - def change_motors( - self, - motor_x: "str", - motor_y: "str", - motor_x_entry: "str" = None, - motor_y_entry: "str" = None, - validate_bec: "bool" = True, - ) -> "None": - """ - Change the active motors for the plot. - - Args: - motor_x(str): Motor name for the X axis. - motor_y(str): Motor name for the Y axis. - motor_x_entry(str): Motor entry for the X axis. - motor_y_entry(str): Motor entry for the Y axis. - validate_bec(bool, optional): If True, validate the signal with BEC. Defaults to True. - """ - - @rpc_call - def set_max_points(self, max_points: "int") -> "None": - """ - Set the maximum number of points to display. - - Args: - max_points(int): Maximum number of points to display. - """ - - @rpc_call - def set_precision(self, precision: "int") -> "None": - """ - Set the decimal precision of the motor position. - - Args: - precision(int): Decimal precision of the motor position. - """ - - @rpc_call - def set_num_dim_points(self, num_dim_points: "int") -> "None": - """ - Set the number of dim points for the motor map. - - Args: - num_dim_points(int): Number of dim points. - """ - - @rpc_call - def set_background_value(self, background_value: "int") -> "None": - """ - Set the background value of the motor map. - - Args: - background_value(int): Background value of the motor map. - """ - - @rpc_call - def set_scatter_size(self, scatter_size: "int") -> "None": - """ - Set the scatter size of the motor map plot. - - Args: - scatter_size(int): Size of the scatter points. - """ - - @rpc_call - def get_data(self) -> "dict": - """ - Get the data of the motor map. - Returns: - dict: Data of the motor map. - """ - - -class BECDock(RPCBase): - @property - @rpc_call - def config_dict(self) -> "dict": - """ - Get the configuration of the widget. - - Returns: - dict: The configuration of the widget. - """ - - @property - @rpc_call - def rpc_id(self) -> "str": - """ - Get the RPC ID of the widget. - """ - - @property - @rpc_call - def widget_list(self) -> "list[BECConnector]": - """ - Get the widgets in the dock. - - Returns: - widgets(list): The widgets in the dock. - """ - - @rpc_call - def show_title_bar(self): - """ - Hide the title bar of the dock. - """ - - @rpc_call - def hide_title_bar(self): - """ - Hide the title bar of the dock. - """ - - @rpc_call - def get_widgets_positions(self) -> "dict": - """ - Get the positions of the widgets in the dock. - - Returns: - dict: The positions of the widgets in the dock as dict -> {(row, col, rowspan, colspan):widget} - """ - - @rpc_call - def set_title(self, title: "str"): - """ - Set the title of the dock. - - Args: - title(str): The title of the dock. - """ - - @rpc_call - def add_widget( - self, - widget: "BECConnector | str", - row=None, - col=0, - rowspan=1, - colspan=1, - shift: "Literal['down', 'up', 'left', 'right']" = "down", - ) -> "BECConnector": - """ - Add a widget to the dock. - - Args: - widget(QWidget): The widget to add. - row(int): The row to add the widget to. If None, the widget will be added to the next available row. - col(int): The column to add the widget to. - rowspan(int): The number of rows the widget should span. - colspan(int): The number of columns the widget should span. - shift(Literal["down", "up", "left", "right"]): The direction to shift the widgets if the position is occupied. - """ - - @rpc_call - def list_eligible_widgets(self) -> "list": - """ - List all widgets that can be added to the dock. - - Returns: - list: The list of eligible widgets. - """ - - @rpc_call - def move_widget(self, widget: "QWidget", new_row: "int", new_col: "int"): - """ - Move a widget to a new position in the layout. - - Args: - widget(QWidget): The widget to move. - new_row(int): The new row to move the widget to. - new_col(int): The new column to move the widget to. - """ - - @rpc_call - def remove_widget(self, widget_rpc_id: "str"): - """ - Remove a widget from the dock. - - Args: - widget_rpc_id(str): The ID of the widget to remove. - """ - - @rpc_call - def remove(self): - """ - Remove the dock from the parent dock area. - """ - - @rpc_call - def attach(self): - """ - Attach the dock to the parent dock area. - """ - - @rpc_call - def detach(self): - """ - Detach the dock from the parent dock area. - """ - - -class BECDockArea(RPCBase, BECGuiClientMixin): - @property - @rpc_call - def config_dict(self) -> "dict": - """ - Get the configuration of the widget. - - Returns: - dict: The configuration of the widget. - """ - - @property - @rpc_call - def panels(self) -> "dict[str, BECDock]": - """ - Get the docks in the dock area. - Returns: - dock_dict(dict): The docks in the dock area. - """ - - @rpc_call - def save_state(self) -> "dict": - """ - Save the state of the dock area. - - Returns: - dict: The state of the dock area. - """ - - @rpc_call - def remove_dock(self, name: "str"): - """ - Remove a dock by name and ensure it is properly closed and cleaned up. - - Args: - name(str): The name of the dock to remove. - """ - - @rpc_call - def restore_state( - self, state: "dict" = None, missing: "Literal['ignore', 'error']" = "ignore", extra="bottom" - ): - """ - Restore the state of the dock area. If no state is provided, the last state is restored. - - Args: - state(dict): The state to restore. - missing(Literal['ignore','error']): What to do if a dock is missing. - extra(str): Extra docks that are in the dockarea but that are not mentioned in state will be added to the bottom of the dockarea, unless otherwise specified by the extra argument. - """ - - @rpc_call - def add_dock( - self, - name: "str" = None, - position: "Literal['bottom', 'top', 'left', 'right', 'above', 'below']" = None, - relative_to: "BECDock | None" = None, - closable: "bool" = False, - floating: "bool" = False, - prefix: "str" = "dock", - widget: "str | QWidget | None" = None, - row: "int" = None, - col: "int" = 0, - rowspan: "int" = 1, - colspan: "int" = 1, - ) -> "BECDock": - """ - Add a dock to the dock area. Dock has QGridLayout as layout manager by default. - - Args: - name(str): The name of the dock to be displayed and for further references. Has to be unique. - position(Literal["bottom", "top", "left", "right", "above", "below"]): The position of the dock. - relative_to(BECDock): The dock to which the new dock should be added relative to. - closable(bool): Whether the dock is closable. - floating(bool): Whether the dock is detached after creating. - prefix(str): The prefix for the dock name if no name is provided. - widget(str|QWidget|None): The widget to be added to the dock. While using RPC, only BEC RPC widgets from RPCWidgetHandler are allowed. - row(int): The row of the added widget. - col(int): The column of the added widget. - rowspan(int): The rowspan of the added widget. - colspan(int): The colspan of the added widget. - - Returns: - BECDock: The created dock. - """ - - @rpc_call - def clear_all(self): - """ - Close all docks and remove all temp areas. - """ - - @rpc_call - def detach_dock(self, dock_name: "str") -> "BECDock": - """ - Undock a dock from the dock area. - - Args: - dock_name(str): The dock to undock. - - Returns: - BECDock: The undocked dock. - """ - - @rpc_call - def attach_all(self): - """ - Return all floating docks to the dock area. - """ - - @rpc_call - def get_all_rpc(self) -> "dict": - """ - Get all registered RPC objects. - """ - - @property - @rpc_call - def temp_areas(self) -> "list": - """ - Get the temporary areas in the dock area. - - Returns: - list: The temporary areas in the dock area. + Reset the connections for the ring widget. Disconnect the current slot and endpoint. """ @@ -1836,144 +1913,6 @@ class SpiralProgressBar(RPCBase): """ -class Ring(RPCBase): - @rpc_call - def get_all_rpc(self) -> "dict": - """ - Get all registered RPC objects. - """ - - @property - @rpc_call - def rpc_id(self) -> "str": - """ - Get the RPC ID of the widget. - """ - - @property - @rpc_call - def config_dict(self) -> "dict": - """ - Get the configuration of the widget. - - Returns: - dict: The configuration of the widget. - """ - - @rpc_call - def set_value(self, value: "int | float"): - """ - Set the value for the ring widget - - Args: - value(int | float): Value for the ring widget - """ - - @rpc_call - def set_color(self, color: "str | tuple"): - """ - Set the color for the ring widget - - Args: - color(str | tuple): Color for the ring widget. Can be HEX code or tuple (R, G, B, A). - """ - - @rpc_call - def set_background(self, color: "str | tuple"): - """ - Set the background color for the ring widget - - Args: - color(str | tuple): Background color for the ring widget. Can be HEX code or tuple (R, G, B, A). - """ - - @rpc_call - def set_line_width(self, width: "int"): - """ - Set the line width for the ring widget - - Args: - width(int): Line width for the ring widget - """ - - @rpc_call - def set_min_max_values(self, min_value: "int | float", max_value: "int | float"): - """ - Set the min and max values for the ring widget. - - Args: - min_value(int | float): Minimum value for the ring widget - max_value(int | float): Maximum value for the ring widget - """ - - @rpc_call - def set_start_angle(self, start_angle: "int"): - """ - Set the start angle for the ring widget - - Args: - start_angle(int): Start angle for the ring widget in degrees - """ - - @rpc_call - def set_update(self, mode: "Literal['manual', 'scan', 'device']", device: "str" = None): - """ - Set the update mode for the ring widget. - Modes: - - "manual": Manual update mode, the value is set by the user. - - "scan": Update mode for the scan progress. The value is updated by the current scan progress. - - "device": Update mode for the device readback. The value is updated by the device readback. Take into account that user has to set the device name and limits. - - Args: - mode(str): Update mode for the ring widget. Can be "manual", "scan" or "device" - device(str): Device name for the device readback mode, only used when mode is "device" - """ - - @rpc_call - def reset_connection(self): - """ - Reset the connections for the ring widget. Disconnect the current slot and endpoint. - """ - - -class WebsiteWidget(RPCBase): - @rpc_call - def set_url(self, url: str) -> None: - """ - Set the url of the website widget - - Args: - url (str): The url to set - """ - - @rpc_call - def get_url(self) -> str: - """ - Get the current url of the website widget - - Returns: - str: The current url - """ - - @rpc_call - def reload(self): - """ - Reload the website - """ - - @rpc_call - def back(self): - """ - Go back in the history - """ - - @rpc_call - def forward(self): - """ - Go forward in the history - """ - - class WebsiteWidget(RPCBase): @rpc_call def set_url(self, url: str) -> None: diff --git a/bec_widgets/cli/generate_cli.py b/bec_widgets/cli/generate_cli.py index d6d4dc5f..fd3f331b 100644 --- a/bec_widgets/cli/generate_cli.py +++ b/bec_widgets/cli/generate_cli.py @@ -1,10 +1,17 @@ # pylint: disable=missing-module-docstring from __future__ import annotations +import argparse +import importlib import inspect +import os import sys +from typing import Literal import black +from qtpy.QtWidgets import QGraphicsWidget, QWidget + +from bec_widgets.utils import BECConnector if sys.version_info >= (3, 11): from typing import get_overloads @@ -22,22 +29,40 @@ else: class ClientGenerator: def __init__(self): self.header = """# This file was automatically generated by generate_cli.py\n -from bec_widgets.cli.client_utils import rpc_call, RPCBase, BECGuiClientMixin -from typing import Literal, Optional, overload""" +import enum +from typing import Literal, Optional, overload + +from bec_widgets.cli.client_utils import BECGuiClientMixin, RPCBase, rpc_call""" self.content = "" - def generate_client(self, published_classes: list): + def generate_client( + self, published_classes: dict[Literal["connector_classes", "top_level_classes"], list[type]] + ): """ Generate the client for the published classes. Args: - published_classes(list): The list of published classes (e.g. [BECWaveform1D, BECFigure]). + published_classes(dict): A dictionary with keys "connector_classes" and "top_level_classes" and values as lists of classes. """ - for cls in published_classes: + self.write_client_enum(published_classes["top_level_classes"]) + for cls in published_classes["connector_classes"]: self.content += "\n\n" self.generate_content_for_class(cls) + def write_client_enum(self, published_classes: list[type]): + """ + Write the client enum to the content. + """ + self.content += """ +class Widgets(str, enum.Enum): + \"\"\" + Enum for the available widgets. + \"\"\" + """ + for cls in published_classes: + self.content += f'{cls.__name__} = "{cls.__name__}"\n ' + def generate_content_for_class(self, cls): """ Generate the content for the class. @@ -104,38 +129,74 @@ class {class_name}(RPCBase):""" with open(file_name, "w", encoding="utf-8") as file: file.write(formatted_content) + @staticmethod + def get_rpc_classes( + repo_name: str, + ) -> dict[Literal["connector_classes", "top_level_classes"], list[type]]: + """ + Get all RPC-enabled classes in the specified repository. + + Args: + repo_name(str): The name of the repository. + + Returns: + dict: A dictionary with keys "connector_classes" and "top_level_classes" and values as lists of classes. + """ + connector_classes = [] + top_level_classes = [] + anchor_module = importlib.import_module(f"{repo_name}.widgets") + directory = os.path.dirname(anchor_module.__file__) + for root, _, files in sorted(os.walk(directory)): + for file in files: + if not file.endswith(".py") or file.startswith("__"): + continue + + path = os.path.join(root, file) + subs = os.path.dirname(os.path.relpath(path, directory)).split("/") + if len(subs) == 1 and not subs[0]: + module_name = file.split(".")[0] + else: + module_name = ".".join(subs + [file.split(".")[0]]) + + module = importlib.import_module(f"{repo_name}.widgets.{module_name}") + + for name in dir(module): + obj = getattr(module, name) + if not hasattr(obj, "__module__") or obj.__module__ != module.__name__: + continue + if isinstance(obj, type) and issubclass(obj, BECConnector): + connector_classes.append(obj) + if len(subs) == 1 and ( + issubclass(obj, QWidget) or issubclass(obj, QGraphicsWidget) + ): + top_level_classes.append(obj) + + return {"connector_classes": connector_classes, "top_level_classes": top_level_classes} + + +def main(): + """ + Main entry point for the script, controlled by command line arguments. + """ + + parser = argparse.ArgumentParser(description="Auto-generate the client for RPC widgets") + parser.add_argument("--core", action="store_true", help="Whether to generate the core client") + + args = parser.parse_args() + + if args.core: + current_path = os.path.dirname(__file__) + client_path = os.path.join(current_path, "client.py") + + rpc_classes = ClientGenerator.get_rpc_classes("bec_widgets") + rpc_classes["connector_classes"].append(BECConnector) # Not sure if this is necessary + rpc_classes["connector_classes"].sort(key=lambda x: x.__name__) + + generator = ClientGenerator() + generator.generate_client(rpc_classes) + generator.write(client_path) + if __name__ == "__main__": # pragma: no cover - import os - - from bec_widgets.utils import BECConnector - from bec_widgets.widgets import BECDock, BECDockArea, BECFigure, SpiralProgressBar - from bec_widgets.widgets.figure.plots.image.image import BECImageShow - from bec_widgets.widgets.figure.plots.image.image_item import BECImageItem - from bec_widgets.widgets.figure.plots.motor_map.motor_map import BECMotorMap - from bec_widgets.widgets.figure.plots.plot_base import BECPlotBase - from bec_widgets.widgets.figure.plots.waveform.waveform import BECWaveform - from bec_widgets.widgets.figure.plots.waveform.waveform_curve import BECCurve - from bec_widgets.widgets.spiral_progress_bar.ring import Ring - from bec_widgets.widgets.website.website import WebsiteWidget - - current_path = os.path.dirname(__file__) - client_path = os.path.join(current_path, "client.py") - clss = [ - BECPlotBase, - BECWaveform, - BECFigure, - BECCurve, - BECImageShow, - BECConnector, - BECImageItem, - BECMotorMap, - BECDock, - BECDockArea, - SpiralProgressBar, - Ring, - WebsiteWidget, - ] - generator = ClientGenerator() - generator.generate_client(clss) - generator.write(client_path) + sys.argv = ["generate_cli.py", "--core"] + main() diff --git a/tests/unit_tests/test_generate_cli_client.py b/tests/unit_tests/test_generate_cli_client.py index 37c7f7f1..1f0f6dec 100644 --- a/tests/unit_tests/test_generate_cli_client.py +++ b/tests/unit_tests/test_generate_cli_client.py @@ -1,7 +1,6 @@ from textwrap import dedent import black -import pytest from bec_widgets.cli.generate_cli import ClientGenerator @@ -33,16 +32,31 @@ class MockBECFigure: def test_client_generator_with_black_formatting(): generator = ClientGenerator() - generator.generate_client([MockBECWaveform1D, MockBECFigure]) + rpc_classes = { + "connector_classes": [MockBECWaveform1D, MockBECFigure], + "top_level_classes": [MockBECFigure], + } + generator.generate_client(rpc_classes) # Format the expected output with black to ensure it matches the generator output expected_output = dedent( '''\ # This file was automatically generated by generate_cli.py - from bec_widgets.cli.client_utils import rpc_call, RPCBase, BECGuiClientMixin + import enum from typing import Literal, Optional, overload + from bec_widgets.cli.client_utils import BECGuiClientMixin, RPCBase, rpc_call + + + class Widgets(str, enum.Enum): + """ + Enum for the available widgets. + """ + + MockBECFigure = "MockBECFigure" + + class MockBECWaveform1D(RPCBase): @rpc_call def set_frequency(self, frequency: float) -> list: @@ -79,3 +93,17 @@ def test_client_generator_with_black_formatting(): ) assert expected_output_formatted == generated_output_formatted + + +def test_client_generator_classes(): + generator = ClientGenerator() + out = generator.get_rpc_classes("bec_widgets") + assert list(out.keys()) == ["connector_classes", "top_level_classes"] + connector_cls_names = [cls.__name__ for cls in out["connector_classes"]] + top_level_cls_names = [cls.__name__ for cls in out["top_level_classes"]] + + assert "BECFigure" in connector_cls_names + assert "BECWaveform" in connector_cls_names + assert "BECDockArea" in top_level_cls_names + assert "BECFigure" in top_level_cls_names + assert "BECWaveform" not in top_level_cls_names