diff --git a/pyproject.toml b/pyproject.toml index 43891f5..a053dca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ license = "MIT" python = ">=3.8, <3.12" h5py = ">=3.6.0" ipympl = ">=0.9.1" -ipywidgets = ">=7.7.1" +ipywidgets = ">=8.1.1" matplotlib = ">=3.5.1" numpy = ">=1.21.6" pynxtools = ">=0.0.9" diff --git a/specsanalyzer/core.py b/specsanalyzer/core.py index 31aacea..7873700 100755 --- a/specsanalyzer/core.py +++ b/specsanalyzer/core.py @@ -8,8 +8,12 @@ from typing import Tuple from typing import Union +import ipywidgets as ipw +import matplotlib +import matplotlib.pyplot as plt import numpy as np import xarray as xr +from IPython.display import display from specsanalyzer import io from specsanalyzer.config import parse_config @@ -45,7 +49,8 @@ def __init__( **kwds, ) self._attributes = MetaHandler(meta=metadata) - + self._data_array = None + self.print_msg = True try: self._config["calib2d_dict"] = io.parse_calib2d_to_dict( self._config["calib2d_file"], @@ -95,13 +100,10 @@ def convert_image( ) -> xr.DataArray: """Converts an imagin in physical unit data, angle vs energy - Args: raw_img (np.ndarray): Raw image data, numpy 2d matrix - lens_mode (str): - analzser lens mode, check calib2d for a list - of modes Camelback naming convention e.g. "WideAngleMode" - + lens_mode (str): analzser lens mode, check calib2d for a list + of modes Camelcase naming convention e.g. "WideAngleMode" kinetic_energy (float): set analyser kinetic energy pass_energy (float): set analyser pass energy work_function (float): set analyser work function @@ -228,29 +230,300 @@ def convert_image( dims=["Position", "Ekin"], ) - # TODO discuss how to handle cropping. Can he store one set of cropping - # parameters in the config, or should we store one set per pass energy/ - # lens mode/ kinetic energy in the dict? - + # Handle cropping based on parameters stored in correction dictionary crop = kwds.pop("crop", self._config.get("crop", False)) if crop: try: - ek_min = kwds.pop("ek_min", self._config["ek_min"]) - ek_max = kwds.pop("ek_max", self._config["ek_max"]) - ang_min = kwds.pop("ang_min", self._config["ang_min"]) - ang_max = kwds.pop("ang_max", self._config["ang_max"]) - data_array = crop_xarray( - data_array, - ang_min, - ang_max, - ek_min, - ek_max, - ) + range_dict: dict = self._correction_matrix_dict[lens_mode][kinetic_energy][ + pass_energy + ][work_function]["crop_params"] + ang_min = range_dict["ang_min"] + ang_max = range_dict["ang_max"] + ek_min = range_dict["ek_min"] + ek_max = range_dict["ek_max"] + if self.print_msg: + print("Using saved crop parameters...") + data_array = crop_xarray(data_array, ang_min, ang_max, ek_min, ek_max) except KeyError: - pass + try: + ang_range_min = ( + kwds["ang_range_min"] + if "ang_range_min" in kwds + else self._config["ang_range_min"] + ) + ang_range_max = ( + kwds["ang_range_max"] + if "ang_range_max" in kwds + else self._config["ang_range_max"] + ) + ek_range_min = ( + kwds["ek_range_min"] + if "ek_range_min" in kwds + else self._config["ek_range_min"] + ) + ek_range_max = ( + kwds["ek_range_max"] + if "ek_range_max" in kwds + else self._config["ek_range_max"] + ) + ang_min = ( + ang_range_min + * ( + data_array.coords[data_array.dims[0]][-1] + - data_array.coords[data_array.dims[0]][0] + ) + + data_array.coords[data_array.dims[0]][0] + ) + ang_max = ( + ang_range_max + * ( + data_array.coords[data_array.dims[0]][-1] + - data_array.coords[data_array.dims[0]][0] + ) + + data_array.coords[data_array.dims[0]][0] + ) + ek_min = ( + ek_range_min + * ( + data_array.coords[data_array.dims[1]][-1] + - data_array.coords[data_array.dims[1]][0] + ) + + data_array.coords[data_array.dims[1]][0] + ) + ek_max = ( + ek_range_max + * ( + data_array.coords[data_array.dims[1]][-1] + - data_array.coords[data_array.dims[1]][0] + ) + + data_array.coords[data_array.dims[1]][0] + ) + if self.print_msg: + print("Cropping parameters not found, using cropping ranges from config...") + data_array = crop_xarray(data_array, ang_min, ang_max, ek_min, ek_max) + except KeyError: + if self.print_msg: + print( + "Warning: Cropping parameters not found, " + "use method crop_tool() after loading.", + ) return data_array + def crop_tool( + self, + raw_img: np.ndarray, + lens_mode: str, + kinetic_energy: float, + pass_energy: float, + work_function: float, + apply: bool = False, + **kwds, + ): + """Crop tool for selecting cropping parameters + Args: + raw_img (np.ndarray): Raw image data, numpy 2d matrix + lens_mode (str): analzser lens mode, check calib2d for a list + of modes Camelcase naming convention e.g. "WideAngleMode" + kinetic_energy (float): set analyser kinetic energy + pass_energy (float): set analyser pass energy + work_function (float): set analyser work function + apply (bool, optional): Option to directly apply the pre-selected cropping parameters. + Defaults to False. + **kwds: Keyword parameters for the crop tool: + + -ek_range_min + -ek_range_max + -ang_range_min + -ang_range_max + """ + + data_array = self.convert_image( + raw_img=raw_img, + lens_mode=lens_mode, + kinetic_energy=kinetic_energy, + pass_energy=pass_energy, + work_function=work_function, + crop=False, + ) + + matplotlib.use("module://ipympl.backend_nbagg") + fig = plt.figure() + ax = fig.add_subplot(111) + try: + mesh_obj = data_array.plot(ax=ax) + except AttributeError: + print("Load the scan first!") + raise + + lineh1 = ax.axhline(y=data_array.Angle[0]) + lineh2 = ax.axhline(y=data_array.Angle[-1]) + linev1 = ax.axvline(x=data_array.Ekin[0]) + linev2 = ax.axvline(x=data_array.Ekin[-1]) + + try: + range_dict = self._correction_matrix_dict[lens_mode][kinetic_energy][pass_energy][ + work_function + ]["crop_params"] + + ek_min = range_dict["ek_min"] + ek_max = range_dict["ek_max"] + ang_min = range_dict["ang_min"] + ang_max = range_dict["ang_max"] + except KeyError: + try: + ang_range_min = ( + kwds["ang_range_min"] + if "ang_range_min" in kwds + else self._config["ang_range_min"] + ) + ang_range_max = ( + kwds["ang_range_max"] + if "ang_range_max" in kwds + else self._config["ang_range_max"] + ) + ek_range_min = ( + kwds["ek_range_min"] if "ek_range_min" in kwds else self._config["ek_range_min"] + ) + ek_range_max = ( + kwds["ek_range_max"] if "ek_range_max" in kwds else self._config["ek_range_max"] + ) + ang_min = ( + ang_range_min + * ( + data_array.coords[data_array.dims[0]][-1] + - data_array.coords[data_array.dims[0]][0] + ) + + data_array.coords[data_array.dims[0]][0] + ) + ang_max = ( + ang_range_max + * ( + data_array.coords[data_array.dims[0]][-1] + - data_array.coords[data_array.dims[0]][0] + ) + + data_array.coords[data_array.dims[0]][0] + ) + ek_min = ( + ek_range_min + * ( + data_array.coords[data_array.dims[1]][-1] + - data_array.coords[data_array.dims[1]][0] + ) + + data_array.coords[data_array.dims[1]][0] + ) + ek_max = ( + ek_range_max + * ( + data_array.coords[data_array.dims[1]][-1] + - data_array.coords[data_array.dims[1]][0] + ) + + data_array.coords[data_array.dims[1]][0] + ) + except KeyError: + ek_min = data_array.coords[data_array.dims[1]][0] + ek_max = data_array.coords[data_array.dims[1]][-1] + ang_min = data_array.coords[data_array.dims[0]][0] + ang_max = data_array.coords[data_array.dims[0]][-1] + + vline_range = [ek_min, ek_max] + hline_range = [ang_min, ang_max] + + vline_slider = ipw.FloatRangeSlider( + description="Ekin", + value=vline_range, + min=data_array.Ekin[0], + max=data_array.Ekin[-1], + step=0.1, + ) + hline_slider = ipw.FloatRangeSlider( + description="Angle", + value=hline_range, + min=data_array.Angle[0], + max=data_array.Angle[-1], + step=0.1, + ) + clim_slider = ipw.FloatRangeSlider( + description="colorbar limits", + value=[data_array.data.min(), data_array.data.max()], + min=data_array.data.min(), + max=data_array.data.max(), + ) + + def update(hline, vline, v_vals): + lineh1.set_ydata(hline[0]) + lineh2.set_ydata(hline[1]) + linev1.set_xdata(vline[0]) + linev2.set_xdata(vline[1]) + mesh_obj.set_clim(vmin=v_vals[0], vmax=v_vals[1]) + fig.canvas.draw_idle() + + ipw.interact( + update, + hline=hline_slider, + vline=vline_slider, + v_vals=clim_slider, + ) + + def cropit(val): # pylint: disable=unused-argument + ang_min = min(hline_slider.value) + ang_max = max(hline_slider.value) + ek_min = min(vline_slider.value) + ek_max = max(vline_slider.value) + self._data_array = crop_xarray(data_array, ang_min, ang_max, ek_min, ek_max) + self._correction_matrix_dict[lens_mode][kinetic_energy][pass_energy][work_function] = { + "crop_params": { + "ek_min": ek_min, + "ek_max": ek_max, + "ang_min": ang_min, + "ang_max": ang_max, + }, + } + self._config["ek_range_min"] = ( + (ek_min - data_array.coords[data_array.dims[1]][0]) + / ( + data_array.coords[data_array.dims[1]][-1] + - data_array.coords[data_array.dims[1]][0] + ) + ).item() + self._config["ek_range_max"] = ( + (ek_max - data_array.coords[data_array.dims[1]][0]) + / ( + data_array.coords[data_array.dims[1]][-1] + - data_array.coords[data_array.dims[1]][0] + ) + ).item() + self._config["ang_range_min"] = ( + (ang_min - data_array.coords[data_array.dims[0]][0]) + / ( + data_array.coords[data_array.dims[0]][-1] + - data_array.coords[data_array.dims[0]][0] + ) + ).item() + self._config["ang_range_max"] = ( + (ang_max - data_array.coords[data_array.dims[0]][0]) + / ( + data_array.coords[data_array.dims[0]][-1] + - data_array.coords[data_array.dims[0]][0] + ) + ).item() + + ax.cla() + self._data_array.plot(ax=ax, add_colorbar=False) + fig.canvas.draw_idle() + + vline_slider.close() + hline_slider.close() + clim_slider.close() + apply_button.close() + + apply_button = ipw.Button(description="Crop") + display(apply_button) + apply_button.on_click(cropit) + plt.show() + if apply: + cropit("") + def mergedicts( dict1: dict, @@ -261,7 +534,7 @@ def mergedicts( Args: dict1 (dict): dictionary 1 - dict2 (dict): dictiontary 2 + dict2 (dict): dictionary 2 Yields: dict: merged dictionary generator diff --git a/specsscan/config/default.yaml b/specsscan/config/default.yaml index f753580..f245a65 100644 --- a/specsscan/config/default.yaml +++ b/specsscan/config/default.yaml @@ -16,3 +16,4 @@ units: azimuth: "degree" polar: "degree" voltage: "V" + temperature: "K" diff --git a/specsscan/core.py b/specsscan/core.py index 88c700b..6e58dec 100755 --- a/specsscan/core.py +++ b/specsscan/core.py @@ -11,9 +11,11 @@ from typing import Sequence from typing import Union +import matplotlib import numpy as np import xarray as xr + from specsanalyzer import SpecsAnalyzer from specsanalyzer.config import parse_config from specsanalyzer.io import to_h5 @@ -26,7 +28,6 @@ from specsscan.helpers import parse_info_to_dict from specsscan.helpers import parse_lut_to_df -# from specsanalyzer.io import to_h5, load_h5, to_tiff, load_tiff package_dir = os.path.dirname(find_spec("specsscan").origin) @@ -103,6 +104,11 @@ def config(self, config: Union[dict, str]): except KeyError: self.spa = SpecsAnalyzer() + @property + def result(self): + """Get result xarray""" + return self._result + def load_scan( self, scan: int, @@ -114,6 +120,7 @@ def load_scan( Sequence[slice], ] = None, metadata: dict = None, + **kwds, ) -> xr.DataArray: """Load scan with given scan number. When iterations is given, average is performed over the iterations over @@ -130,6 +137,8 @@ def load_scan( np.s_[1:10, 15, -1] would be a valid input for iterations. metadata (dict, optional): Metadata dictionary with additional metadata for the scan + **kwds: Additional arguments for the SpecsAnalyzer converter. For ex., passing + crop=True crops the data if cropping data is already present in the given instance. Raises: FileNotFoundError, IndexError @@ -138,6 +147,7 @@ def load_scan( and optionally a third scanned axis (for ex., delay, temperature) as coordinates. """ + if path: path = Path(path).joinpath(str(scan).zfill(4)) if not path.is_dir(): @@ -192,8 +202,11 @@ def load_scan( kin_energy, pass_energy, work_function, + **kwds, ), ) + self.spa.print_msg = False + self.spa.print_msg = True coords, dim = get_coords( scan_path=path, @@ -261,20 +274,36 @@ def load_scan( self.metadata.update(**metadata) res_xarray.attrs["metadata"] = self.metadata - self._result = res_xarray return res_xarray + def crop_tool(self, **kwds): + """ + Croping tool interface to crop_tool method + of the SpecsAnalyzer class. + """ + matplotlib.use("module://ipympl.backend_nbagg") + try: + image = self.metadata["loader"]["raw_data"][0] + except KeyError as exc: + raise ValueError("No image loaded, load image first!") from exc + self.spa.crop_tool( + image, + self._scan_info["LensMode"], + self._scan_info["KineticEnergy"], + self._scan_info["PassEnergy"], + self._scan_info["WorkFunction"], + **kwds, + ) + def check_scan( self, scan: int, - delays: Union[ - Sequence[int], - int, - ], + delays: Union[Sequence[int], int], path: Union[str, Path] = "", metadata: dict = None, + **kwds, ) -> xr.DataArray: """Function to explore a given 3-D scan as a function of iterations for a given range of delays @@ -285,6 +314,8 @@ def check_scan( path: Either a string of the path to the folder containing the scan or a Path object metadata (dict, optional): Metadata dictionary with additional metadata for the scan + **kwds: Additional arguments for the SpecsAnalyzer converter. For ex., passing + crop=True crops the data if cropping data is already present in the given instance. Raises: FileNotFoundError Returns: @@ -350,8 +381,11 @@ def check_scan( kin_energy, pass_energy, work_function, + **kwds, ), ) + self.spa.print_msg = False + self.spa.print_msg = True dims = get_coords( scan_path=path, diff --git a/specsscan/helpers.py b/specsscan/helpers.py index b355af4..a39614d 100644 --- a/specsscan/helpers.py +++ b/specsscan/helpers.py @@ -36,32 +36,36 @@ def load_images( Sequence[slice], ] = None, tqdm_enable_nested: bool = False, -) -> np.ndarray: +) -> List[np.ndarray]: """Loads a 2D/3D numpy array of images for the given - scan path with an optional averaging - over the given iterations/delays. The function provides - functionality to both load_scan and check_scan methods of - the SpecsScan class. When iterations/delays is provided, - average is performed over the iterations/delays for all - delays/iterations. + scan path with an optional averaging + over the given iterations/delays. The function provides + functionality to both load_scan and check_scan methods of + the SpecsScan class. When iterations/delays is provided, + average is performed over the iterations/delays for all + delays/iterations. + Args: - scan_path: object of class Path pointing - to the scan folder - df_lut: Pandas dataframe containing the contents of LUT.txt - as obtained from parse_lut_to_df() - iterations: A 1-D array of the indices of iterations over - which the images are to be averaged. The array - can be a list, numpy array or a Tuple consisting of - slice objects and integers. For ex., - np.s_[1:10, 15, -1] would be a valid input. - delays: A 1-D array of the indices of delays over - which the images are to be averaged. The array can - be a list, numpy array or a Tuple consisting of - slice objects and integers. For ex., - np.s_[1:10, 15, -1] would be a valid input. + scan_path (Path): object of class Path pointing to the scan folder + df_lut (Union[pd.DataFrame, None], optional): Pandas dataframe containing the contents + of LUT.txt as obtained from parse_lut_to_df(). Defaults to None. + iterations (Union[ np.ndarray, slice, Sequence[int], Sequence[slice], ], optional): A 1-D + array of the indices of iterations over which the images are to be averaged. The array + can be a list, numpy array or a Tuple consisting of slice objects and integers. For + ex., np.s_[1:10, 15, -1] would be a valid input. Defaults to None. + delays (Union[ np.ndarray, slice, int, Sequence[int], Sequence[slice], ], optional): A 1-D + array of the indices of delays over which the images are to be averaged. The array can + be a list, numpy array or a Tuple consisting of slice objects and integers. For ex., + np.s_[1:10, 15, -1] would be a valid input. Defaults to None. + tqdm_enable_nested (bool, optional): Option to enable a nested progress bar. + Defaults to False. + + Raises: + ValueError: Raised if both iterations and delays is provided. + IndexError: Raised if no valid dimension for averaging is found. + Returns: - data: A 2-D or 3-D (concatenated) numpy array consisting - of raw data + List[np.ndarray]: A list of 2-D numpy arrays of raw data """ scan_list = sorted( @@ -135,7 +139,7 @@ def load_images( new_im = np.loadtxt(file, delimiter="\t") data.append(new_im) - return np.array(data) + return data def get_raw2d( @@ -359,6 +363,7 @@ def handle_meta( # pylint:disable=too-many-branches # get metadata from LUT dataframe lut_meta = {} + energy_scan_mode = "fixed" if df_lut is not None: for col in df_lut.columns: col_array = df_lut[f"{col}"].to_numpy() @@ -367,6 +372,10 @@ def handle_meta( # pylint:disable=too-many-branches else: lut_meta[col] = col_array + kinetic_energy = df_lut["KineticEnergy"].to_numpy() + if len(set(kinetic_energy)) > 1 and scan_info["ScanType"] == "voltage": + energy_scan_mode = "sweep" + scan_meta = complete_dictionary(lut_meta, scan_info) # merging two dictionaries # Get metadata from Epics archive, if not present already @@ -376,6 +385,8 @@ def handle_meta( # pylint:disable=too-many-branches config, ) + metadata_dict["scan_info"]["energy_scan_mode"] = energy_scan_mode + lens_modes_all = { "real": config["spa_params"]["calib2d_dict"]["supported_space_modes"], "reciprocal": config["spa_params"]["calib2d_dict"]["supported_angle_modes"], @@ -395,12 +406,6 @@ def handle_meta( # pylint:disable=too-many-branches fast, ] - kinetic_energy = df_lut["KineticEnergy"].to_numpy() - if len(set(kinetic_energy)) > 1 and scan_meta["ScanType"] == "voltage": - metadata_dict["scan_info"]["energy_scan_mode"] = "sweep" - else: - metadata_dict["scan_info"]["energy_scan_mode"] = "fixed" - print("Done!") return metadata_dict diff --git a/tests/test_convert.py b/tests/test_convert.py index d567875..bb7e61e 100755 --- a/tests/test_convert.py +++ b/tests/test_convert.py @@ -199,7 +199,7 @@ def test_conversion(): def test_recycling(): - """Test function for chceking that the class correctly re-uses the + """Test function for checking that the class correctly re-uses the precalculated parameters """ # get the raw data @@ -237,3 +237,118 @@ def test_recycling(): ) assert spa.correction_matrix_dict["old_matrix_check"] is True + + +def test_cropping(): + """Test function for checking that cropping parameters are correctly appield""" + # get the raw data + raw_image_name = os.fspath( + f"{test_dir}/data/dataEPFL/R9132/Data9132_RAWDATA.tsv", + ) + with open(raw_image_name, encoding="utf-8") as file: + tsv_data = np.loadtxt(file, delimiter="\t") + + config_path = os.fspath(f"{test_dir}/data/dataEPFL/config/config.yaml") + spa = SpecsAnalyzer(config=config_path) + lens_mode = "WideAngleMode" + kinetic_energy = 35.000000 + pass_energy = 35.000000 + work_function = 4.2 + + converted = spa.convert_image( + raw_img=tsv_data, + lens_mode=lens_mode, + kinetic_energy=kinetic_energy, + pass_energy=pass_energy, + work_function=work_function, + crop=True, + ) + assert converted.Angle[0] == -18 + assert converted.Angle[-1] == 17.859375 + assert converted.Ekin[0] == 32.69 + assert converted.Ekin[-1] == 37.296569767441866 + + converted = spa.convert_image( + raw_img=tsv_data, + lens_mode=lens_mode, + kinetic_energy=kinetic_energy, + pass_energy=pass_energy, + work_function=work_function, + ek_range_min=0.1, + ek_range_max=0.9, + ang_range_min=0.1, + ang_range_max=0.9, + crop=True, + ) + assert converted.Angle[0] == -14.34375 + assert converted.Angle[-1] == 14.203125 + assert converted.Ekin[0] == 33.16005813953488 + assert converted.Ekin[-1] == 36.82651162790698 + + spa.crop_tool( + raw_img=tsv_data, + lens_mode=lens_mode, + kinetic_energy=kinetic_energy, + pass_energy=pass_energy, + work_function=work_function, + ek_range_min=0.1, + ek_range_max=0.9, + ang_range_min=0.1, + ang_range_max=0.9, + apply=True, + ) + + converted = spa.convert_image( + raw_img=tsv_data, + lens_mode=lens_mode, + kinetic_energy=kinetic_energy, + pass_energy=pass_energy, + work_function=work_function, + crop=True, + ) + + assert converted.Angle[0] == -14.34375 + assert converted.Angle[-1] == 14.203125 + assert converted.Ekin[0] == 33.16005813953488 + assert converted.Ekin[-1] == 36.82651162790698 + + spa.crop_tool( + raw_img=tsv_data, + lens_mode=lens_mode, + kinetic_energy=45.0, + pass_energy=pass_energy, + work_function=work_function, + ek_range_min=0.2, + ek_range_max=0.8, + ang_range_min=0.2, + ang_range_max=0.8, + apply=True, + ) + + converted = spa.convert_image( + raw_img=tsv_data, + lens_mode=lens_mode, + kinetic_energy=50.0, + pass_energy=pass_energy, + work_function=work_function, + crop=True, + ) + + assert converted.Angle[0] == -10.828125 + assert converted.Angle[-1] == 10.6875 + assert converted.Ekin[0] == 48.616686046511624 + assert converted.Ekin[-1] == 51.36988372093023 + + converted = spa.convert_image( + raw_img=tsv_data, + lens_mode=lens_mode, + kinetic_energy=kinetic_energy, + pass_energy=pass_energy, + work_function=work_function, + crop=True, + ) + + assert converted.Angle[0] == -14.34375 + assert converted.Angle[-1] == 14.203125 + assert converted.Ekin[0] == 33.16005813953488 + assert converted.Ekin[-1] == 36.82651162790698 diff --git a/tutorial/example.ipynb b/tutorial/example.ipynb index 3a7860a..54e6f9a 100644 --- a/tutorial/example.ipynb +++ b/tutorial/example.ipynb @@ -23,8 +23,12 @@ "metadata": {}, "outputs": [], "source": [ + "%load_ext autoreload\n", + "%autoreload 2\n", "from specsscan import SpecsScan\n", - "from pathlib import Path" + "import matplotlib.pyplot as plt\n", + "\n", + "%matplotlib widget" ] }, { @@ -58,7 +62,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The load_scan method loads the scan as an xarray along with the metadata needed for nexus conversion. The progress bars can be activated by changing the config parameter, enable_nested_progress_bar, to true in config.yaml " + "The load_scan method loads the scan as an xarray along with the metadata needed for nexus conversion. The progress bars can be activated by changing the config parameter, enable_nested_progress_bar, to true in config.yaml. Additionally, the data can be cropped by passing a boolean \"crop\" to the loader, provided the crop parameters already exist in the given instance. " ] }, { @@ -69,7 +73,8 @@ "source": [ "res_xarray = sps.load_scan(\n", " scan=4450, # Scan number for an example mirror scan\n", - " path = path\n", + " path = path,\n", + " crop=True\n", ")" ] }, @@ -79,7 +84,45 @@ "metadata": {}, "outputs": [], "source": [ - "res_xarray" + "plt.figure()\n", + "res_xarray[:,:,0].plot()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The loader has given a warning saying that the cropping parameters do not exist yet. Therefore, a cropping tool can be used to crop the data while also saving the crop ranges into a class attribute for later scans." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sps.crop_tool()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Press crop applies the cropping to the test image, and stores the cropping information in the class.\n", + "Load the scan again to apply it to all images:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "res_xarray = sps.load_scan(\n", + " scan=4450, # Scan number for an example mirror scan\n", + " path = path,\n", + " crop=True\n", + ")" ] }, { @@ -96,7 +139,7 @@ "metadata": {}, "outputs": [], "source": [ - "res_xarray.dims" + "sps.result.coords" ] }, { @@ -105,7 +148,9 @@ "metadata": {}, "outputs": [], "source": [ - "res_xarray[:,:,0].plot()" + "plt.figure()\n", + "sps.result[:,:,0].plot()\n", + "plt.show()" ] }, { @@ -122,7 +167,7 @@ "metadata": {}, "outputs": [], "source": [ - "res_xarray.attrs[\"metadata\"].keys()" + "sps.result.attrs[\"metadata\"].keys()" ] }, { @@ -139,7 +184,7 @@ "metadata": {}, "outputs": [], "source": [ - "res_xarray_iter = sps.load_scan(\n", + "sps.load_scan(\n", " scan=4450,\n", " path=path,\n", " iterations=[0]\n", @@ -152,7 +197,9 @@ "metadata": {}, "outputs": [], "source": [ - "res_xarray_iter[:,:,0].plot()" + "plt.figure()\n", + "sps.result[:,:,0].plot()\n", + "plt.show()" ] }, { @@ -200,7 +247,7 @@ "metadata": {}, "outputs": [], "source": [ - "from nexusutils.dataconverter.convert import convert" + "from pynxtools.dataconverter.convert import convert" ] }, { @@ -210,9 +257,9 @@ "outputs": [], "source": [ "convert(input_file=[\"../tests/data/phoibos_config.json\", # config file for translating local metadata paths to NeXus paths\n", - " \"../tests/data/phoibos_eln_data.yaml\" # ELN file that adds/overwrites additional metadata \n", + " \"../tests/data/phoibos_eln_data.yaml\" # ELN file that adds/overwrites additional metadata\n", " ],\n", - " objects=res_xarray, # xarray object obtained from the specsscan loader\n", + " objects=sps.result, # xarray object obtained from the specsscan loader\n", " reader='mpes',\n", " nxdl='NXmpes',\n", " output='spectest.mpes.nxs')" @@ -273,9 +320,8 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.0" + "version": "3.8.12" }, - "orig_nbformat": 4, "vscode": { "interpreter": { "hash": "a164666994e9db75450cd7016dd7e51d42ea6e7c1e5e8017af1f8068ca906367"