diff --git a/.gitignore b/.gitignore index cd70700..30897ca 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ build/ dist/ *.egg-info/ venv/ +.vscode diff --git a/xicam/spectral/ingestors/NXcxi_ptycho.py b/xicam/spectral/ingestors/NXcxi_ptycho.py index e56bf6a..0d322ce 100644 --- a/xicam/spectral/ingestors/NXcxi_ptycho.py +++ b/xicam/spectral/ingestors/NXcxi_ptycho.py @@ -66,6 +66,7 @@ def ingest_cxi(paths): sorted_entry_list = sorted(h5_entry_dict.items(), key=lambda item: item[1]) # TODO check if energies are "continuous" or have interruptions # the removal of last for entries is only temporary due to the example dataset + # FIXME what to do if some energies are 'out of range'? del sorted_entry_list[-4:] frames_stack = [] diff --git a/xicam/spectral/operations/decomposition.py b/xicam/spectral/operations/decomposition.py index a5fd43f..cb84caa 100644 --- a/xicam/spectral/operations/decomposition.py +++ b/xicam/spectral/operations/decomposition.py @@ -26,7 +26,7 @@ class svd_solver(enum.Enum): # *[f'component{i}' for i in range(3)], 'energy', 'component_indices') @visible('data', False) -# @input_names('data', 'Number of components', 'Copy', 'Whiten', 'SVD Solver', 'Tolerance', 'Iterated Power', 'Random State') +# @input_names('data', 'energy axis is last', 'Number of components', 'Copy', 'Whiten', 'SVD Solver', 'Tolerance', 'Iterated Power', 'Random State') @intent(PairPlotIntent, "Pair Plot", output_map={"transform_data": "transform_data"}) @intent(ImageIntent, "PCA Transform", output_map={"image": "transform_data", 'xvals': 'component_indices'}, mixins=['SliceSelector'], axes={'t': 2, 'x': 1, 'y': 0, 'c': None}) @intent(ImageIntent, "False-color PCA Transform", output_map={"image": "transform_data", 'xvals': 'component_indices'}, axes={'t': None, 'x': 1, 'y': 0, 'c': 2}) @@ -37,9 +37,8 @@ class svd_solver(enum.Enum): def pca(data:np.ndarray, n_components:Union[int, float, str]=3, copy:bool=True, whiten:bool=False, svd_solver:svd_solver='auto', tol:float=0.0, iterated_power:Union[str, int]='auto', random_state:int=None): pca = PCA(n_components, copy=copy, whiten=whiten, svd_solver=svd_solver, tol=tol, iterated_power=iterated_power, random_state=random_state) - pca.fit(np.asarray(data).reshape(-1, data.shape[2])) - images = pca.transform(np.asarray(data).reshape(-1, data.shape[2])).reshape(data.shape[0],data.shape[1], n_components) - + pca.fit(np.asarray(data).reshape(-1, data.shape[0])) + images = pca.transform(np.asarray(data).reshape(-1, data.shape[0])).reshape(data.shape[1], data.shape[2], 3) return images, pca.explained_variance_ratio_, pca.components_, data.coords['E (eV)'], np.arange(images.shape[-1]) diff --git a/xicam/spectral/projectors/__init__.py b/xicam/spectral/projectors/__init__.py index 16e130c..52a7fcf 100644 --- a/xicam/spectral/projectors/__init__.py +++ b/xicam/spectral/projectors/__init__.py @@ -14,12 +14,10 @@ def project_nxSTXM(run_catalog: BlueskyRun): energy = projection['irmap/DATA/energy']['value'] xdata = getattr(run_catalog, stream).to_dask()[field] # type: xr.DataArray - xdata = np.squeeze(xdata) - xdata = xdata.assign_coords({xdata.dims[0]: energy, xdata.dims[2]: sample_x, xdata.dims[1]: sample_y}) - return xdata.transpose('y (μm)', 'x (μm)', ...) + return [ImageIntent(item_name='IR maps', image=xdata),] def project_nxCXI_ptycho(run_catalog: BlueskyRun): @@ -40,10 +38,13 @@ def project_nxCXI_ptycho(run_catalog: BlueskyRun): rec_data_phase = getattr(run_catalog, phase_rec_stream).to_dask()[phase_rec_field] rec_data_phase = np.squeeze(rec_data_phase) - rec_data_trans = rec_data_trans.assign_coords( - {rec_data_trans.dims[0]: energy, rec_data_trans.dims[1]: coords_y, rec_data_trans.dims[2]: coords_x}) - return [ImageIntent(item_name='Transmission Reconstruction', image=rec_data_trans), + rec_data_trans = rec_data_trans.assign_coords({rec_data_trans.dims[0]: energy, + rec_data_trans.dims[1]: coords_y, + rec_data_trans.dims[2]: coords_x}) + + #TODO add imagemixins to display complex + return [ImageIntent(item_name='ptychography data', image=rec_data_trans), # ImageIntent(image=rec_data_phase, item_name='phase reconstruction') ] @@ -71,4 +72,4 @@ def project_all(run_catalog: BlueskyRun): for projection in run_catalog.metadata['start']['projections']: projector = projection_mapping.get(projection['name']) if projector: - return projector(run_catalog) \ No newline at end of file + return projector(run_catalog) diff --git a/xicam/spectral/stages/__init__.py b/xicam/spectral/stages/__init__.py index 6f5a9f5..6c464fa 100644 --- a/xicam/spectral/stages/__init__.py +++ b/xicam/spectral/stages/__init__.py @@ -1,5 +1,6 @@ import numpy as np import xarray as xr + from databroker.in_memory import BlueskyInMemoryCatalog from qtpy.QtWidgets import QLabel, QComboBox, QHBoxLayout, QWidget, QSpacerItem, QSizePolicy @@ -16,9 +17,10 @@ from xicam.gui.widgets.linearworkfloweditor import WorkflowEditor from databroker.core import BlueskyRun from xicam.core.execution import Workflow +from xicam.core.intents import Intent from xicam.plugins import GUIPlugin from ..widgets.image_viewers import CatalogViewerBlend -from ..projectors import project_nxSTXM, project_all +from ..projectors import project_all class SpectralBase(GUIPlugin): @@ -42,10 +44,16 @@ def __init__(self): super(SpectralBase, self).__init__() def treatment_kwargs(self, workflow): + intent_name = ['hyperspectral_data', 'ptychography data', 'IR maps'] # FIXME: Putting this here for now... self.current_data = None - return {'data': project_all(self.current_catalog)} + projected_data = project_all(self.current_catalog) + if isinstance(projected_data, list): + data_intent = next(filter(lambda intent: intent.item_name in intent_name, iter(projected_data))) + return {'data': data_intent.image} + else: + return {'data': projected_data} def append_treatment(self, result_set): if self.current_data is None: @@ -60,7 +68,7 @@ def appendCatalog(self, run_catalog: BlueskyRun, **kwargs): # catalog.metadata.update(self.schema()) ensemble = Ensemble() ensemble.append_catalog(run_catalog) - self.ensemble_model.add_ensemble(ensemble, project_all) + self.ensemble_model.add_ensemble(ensemble, [project_all]) try: # Apply nxSTXM projection diff --git a/xicam/spectral/workflows/workflows.py b/xicam/spectral/workflows/workflows.py index deba5bb..d66bf7c 100644 --- a/xicam/spectral/workflows/workflows.py +++ b/xicam/spectral/workflows/workflows.py @@ -1,6 +1,8 @@ -from shop.correction.register import RegisterOperation -from shop.correction.filter import MedianFilterOperation, WienerFilterOperation +from pystxmtools.corrections.register import register_operation +from pystxmtools.corrections.filter import median_filter_operation, wiener_filter_operation, denoise_operation, despike_operation +from pystxmtools.corrections.optical_density import calc_opt_density_operation +from pystxmtools.corrections.fitting import lsq_fit_operation # from ..operations.register import RegisterOperation # from shop.correction.filter import median_filter, wiener_filter @@ -13,13 +15,22 @@ def __init__(self): super(StxmWorkflow, self).__init__(name="STXM Workflow") # Create instances of operations - register = RegisterOperation() - wiener = MedianFilterOperation() - median = WienerFilterOperation() + register = register_operation() + wiener = median_filter_operation() + median = wiener_filter_operation() + denoise = denoise_operation() + #TODO: how can calcOD receive IO map in workflow editor + calc_OD = calc_opt_density_operation() + lstsq_fit = lsq_fit_operation() + # Add operation to the workflow self.add_operations(register) self.add_operations(wiener) self.add_operations(median) + self.add_operation(denoise) + self.add_operation(calc_OD) + self.add_operation(lstsq_fit) + # self.auto_connect_all() #connect one operation's output with another operation's input # self.add_link() diff --git a/xicam/tests/test_examples.py b/xicam/tests/test_examples.py index 9691fca..733f0f5 100644 --- a/xicam/tests/test_examples.py +++ b/xicam/tests/test_examples.py @@ -7,24 +7,42 @@ from skimage import data from scipy.ndimage.interpolation import shift -from shop.correction.register import register_frames_stack +from pystxmtools.corrections.register import register_frames_stack -@fixture +# @fixture def test_stack(): image = data.camera() n_frames = 10 - shifts = [(round(random.uniform(1, 50), 2), round(random.uniform(1, 50), 2)) for i in range(n_frames)] - stack = [] + # shifts = (round(random.uniform(1, 50), 2), round(random.uniform(1, 50), 2)) + im_shift_stack = [] for n in range(n_frames): - stack.append(shift(image, shifts[n])) - return np.asarray(stack) + shifts = (round(random.uniform(1, 50), 2), round(random.uniform(1, 50), 2)) + el = [shift(image, shifts), shifts] + im_shift_stack.append(el) + return np.asarray(im_shift_stack) -def test_register_frame_stack(test_stack): + +def test_register_frame_stack(): "Test something in register_frame_stack " - aligned_frames = register_frames_stack(test_stack) - print(aligned_frames.shape) - print(test_stack.shape) + image = data.camera() + n_frames = 10 + # shifts = (round(random.uniform(1, 50), 2), round(random.uniform(1, 50), 2)) + im_stack = [] + shift_stack = [] + for n in range(n_frames-1): + shifts = [round(random.uniform(1, 50), 2), round(random.uniform(1, 50), 2)] + shift_stack.append(shifts) + + shifted_frames = shift(image, shifts) + im_stack.append(shifted_frames) + # aligned_frames, calc_shifts = register_frames_stack(frames=test_stack[:,0]) + aligned_frames, calc_shifts = register_frames_stack(np.asarray(im_stack)) + + return aligned_frames, calc_shifts, shift_stack, shifts, np.asarray(im_stack) - assert aligned_frames.shape[0] == test_stack.shape[0] + # assert calc_shifts == shift_stack + # assert calc_shifts == test_stack[:,1] +if __name__ == "__main__": + test_stack()