Source code for xrf_explorer.server.dim_reduction.general

import logging

from os import makedirs
from os.path import join, isdir, isfile

import numpy as np

from cv2 import imwrite
from scipy.interpolate import NearestNDInterpolator

from xrf_explorer.server.file_system import get_config, get_path_to_generated_folder
from xrf_explorer.server.file_system.cubes import get_elemental_data_cube

LOG: logging.Logger = logging.getLogger(__name__)

MAPPING_IMAGE_NAME: str = 'image_index_to_embedding.png'


[docs] def valid_element(element: int, data_cube: np.ndarray) -> bool: """ Verifies whether the given element is valid for the given data cube. :param element: The element to verify :param data_cube: The data cube to verify the element for :return: True if the element is valid, otherwise False """ # verify valid element total_number_of_elements: int = data_cube.shape[0] if element < 0 or element >= total_number_of_elements: LOG.error(f"Invalid element: {element}") return False return True
[docs] def get_path_to_dr_folder(data_source: str) -> str: """ Get the path to the dimensionality reduction folder for a given datasource. If it does not exist the folder is created. :param data_source: The name of the datasource :return: The path to the dimensionality reduction folder for the given datasource """ # load backend config backend_config: dict = get_config() if not backend_config: # config is empty LOG.error("Config is empty") return "" # Get path to generated folder of the data source path_to_generated_folder: str = get_path_to_generated_folder(data_source) if not path_to_generated_folder: return "" # Path to the dimensionality reduction folder path_to_dr_folder: str = join(path_to_generated_folder, backend_config['dim-reduction']['folder-name']) # Check if the dimensionality reduction folder exists, otherwise create it if not isdir(path_to_dr_folder): makedirs(path_to_dr_folder) LOG.info(f"Created directory {path_to_dr_folder}.") LOG.info(f"Dimensionality reduction folder {data_source} found.") return path_to_dr_folder
[docs] def create_image_of_indices_to_embedding(data_source: str) -> bool: """ Creates the image for polygon selection that decodes to which points in the embedding the pixels of the elemental data cube are mapped. Uses the current embedding and indices to create the image. :param data_source: Name of the data source :return: True if the image was created successfully, otherwise False """ dr_folder: str = get_path_to_dr_folder(data_source) # Get the path to the dimensionality reduction folder elemental_cube: np.ndarray | None = get_elemental_data_cube(data_source) # Load the elemental data cube # Check if the folder and the elemental data cube are loaded if not dr_folder or elemental_cube is None: return False # Load the file embedding.npy try: indices: np.ndarray = np.load(join(dr_folder, 'indices.npy')) all_indices: np.ndarray = np.load(join(dr_folder, 'all_indices.npy')) embedding: np.ndarray = np.load(join(dr_folder, 'embedded_data.npy')) except OSError as e: LOG.error(f"Failed to load indices and/or embedding data. Error: {e}") return False # Get min and max values xmin, ymin = np.min(embedding, axis=0) xmax, ymax = np.max(embedding, axis=0) # Normalize values to be in the range [0, 255] embedding[:, 0] = np.interp(embedding[:, 0], (xmin, xmax), (0, +255)) embedding[:, 1] = np.interp(embedding[:, 1], (ymin, ymax), (0, +255)) LOG.info(f"Creating the interpolator with the data of size: {indices.shape[0]}") interp = NearestNDInterpolator(elemental_cube[:, indices[:, 0], indices[:, 1]].T, embedding) LOG.info(f"Interpolating the data of size: {all_indices.shape[0]}") interpolated = interp(elemental_cube[:, all_indices[:, 0], all_indices[:, 1]].T) # Initialize new image LOG.info("Creating the mapping image") new_image = np.zeros((elemental_cube.shape[1], elemental_cube.shape[2], 3), dtype=np.uint8) # Fill pixels (in BGR format) new_image[all_indices[:, 0], all_indices[:, 1], 0] = 255 new_image[all_indices[:, 0], all_indices[:, 1], 1] = interpolated[:, 1] new_image[all_indices[:, 0], all_indices[:, 1], 2] = interpolated[:, 0] # Create and save the image path_image: str = join(dr_folder, MAPPING_IMAGE_NAME) imwrite(path_image, new_image) LOG.info("Created DR image index to embedding.") return True
[docs] def get_image_of_indices_to_embedding(data_source: str) -> str: """ Returns the path to the image that maps the indices of the elemental data cube to the embedding. :param data_source: Name of the data source :return: Path to the image. If the image is not found, an empty string is returned """ # Get the path to the dimensionality reduction folder dr_folder: str = get_path_to_dr_folder(data_source) if not dr_folder: return "" # Check if the image exists file_path: str = join(dr_folder, MAPPING_IMAGE_NAME) if not isfile(file_path): LOG.error(f"File {MAPPING_IMAGE_NAME} not found.") return "" return join(dr_folder, MAPPING_IMAGE_NAME)