palmettobug.ImageProcessing.ImageAnalysisClass
This module contains the classes / functions used in the back-end of image processing (its front end is the second tab of the program).
Many classes / functions in this file are available in the public (non-GUI) API of PalmettoBUG.
Classes
This handles Image Processing steps of PalmettoBUG, such as conversion from mcd's and segmentation measurements |
Functions
|
This function is the entrypoint for a project using MCDs or TIFFs. It initializes and return an ImageAnalysis object using the |
|
Reads a single txt file (these are backups for if mcd files become corrupted). |
|
Iteratively runs read_txt_file() on each file in a directory, and output .ome.tiffs (at least by file extension) to an output directory. |
|
Function that expands the size of cell masks: |
|
This sets up a folder for single-cell analysis using the CATALYST-derived module of PalmettoBUG. |
Module Contents
- palmettobug.ImageProcessing.ImageAnalysisClass.imc_entrypoint(directory: pathlib.Path | str, resolutions: list[float] = [1.0, 1.0], from_mcds: bool = True) ImageAnalysis
This function is the entrypoint for a project using MCDs or TIFFs. It initializes and return an ImageAnalysis object using the arguments passed in by the user.
- Args:
- directory (Path or string):
This is the path to a folder containing a subfolder /raw with either .tiff or .mcd files inside it
- resolutions (iterable of length two: float, float):
This is the [X, Y] resolutions of the images in micrometers / pixel. The default is 1.0 microns / pixels for both dimensions, as has been usual for IMC.
- from_mcds (boolean):
whether the /raw subfolder contains .mcd files (= True) or .tiff files (= False)
- returns:
a palmettobug.ImageAnalysis object
- palmettobug.ImageProcessing.ImageAnalysisClass.read_txt_file(path: str | pathlib.Path, num_meta_data_columns: int = 6)
Reads a single txt file (these are backups for if mcd files become corrupted).
Assumes that the txt file itself is not corrupted & has six [Arg: num_meta_data_columns] metadata columns before the channels. Also assumes a complete file with X / Y columns, whose values accurately correspond to the X / Y of the image to be generated.
- Args:
- path (str or Path):
the full path to the single .txt file to be read-in
- num_meta_data_columns (integer):
The number of metadata columns in the file. Default is 6, which worked for the files I tested this function on, but I don’t know what is standard / what kind of variability there is in the metadata for these types of files.
- returns:
numpy array, which can be saved as an (.ome).tiff
- palmettobug.ImageProcessing.ImageAnalysisClass.txt_folder_to_tiff_folder(txt_folder: pathlib.Path | str, tiff_folder: pathlib.Path | str, panel: pandas.DataFrame, hpf: float | int = 50, ome_tiff_metadata: bool = False, resolutions: list[float] = [1.0, 1.0], num_meta_data_columns: int = 6) None
Iteratively runs read_txt_file() on each file in a directory, and output .ome.tiffs (at least by file extension) to an output directory.
To actually generate ometiff metadata to be included with the images, two things must occur:
ome_tiff_metadata == True
Resolutions Argument must be provided (default is 1 micrometer/pixel in both X an Y)
- Args:
- txt_folder (Path or str):
the path to a folder where the .txt files to be converted are. Assumes only .txt files are inside this folder
- tiff_folder (Path or str):
the path to the folder where the output .ome.tiff files will be written
- panel (pandas DataFrame):
the panel file. Used to filter out undesirable channels & construct ometiff metadata
- hpf (integer >= 0):
whether to run hot pixel filtering (if hpf != 0) and if hpf is run what threshold to use.
- ome_tiff_metadata (boolean):
whether to generate metadata for the ome.tiff – this does not change the output extension name, which will always be .ome.tiff, but does determine whether the function will attempt to add metadata to the files. If True, then the resolutions argument must be provided, or an error will occur.
- resolutions (list of two floats > 0):
the resolution of the images in X and Y dimensions, in micrometers per pixel. Only used if ome_tiff_metadata == True.
- num_meta_data_columns (integer):
The number of metadata columns in the file. Default is 6, which worked for the files I tested this function on, but I don’t know what is standard / what kind of variability there is in the metadata for these types of files.
- Inputs / Outputs:
- Inputs:
reads each file inside txt_folder (expecting all to be .txt files of the format exported during IMC as backups of .mcd files. )
- Outputs:
writes an .ome.tiff file in tiff_folder for each .txt file read in from txt_folder
- palmettobug.ImageProcessing.ImageAnalysisClass.mask_expand(distance: int, image_source: pathlib.Path | str, output_directory: pathlib.Path | str | None) None
Function that expands the size of cell masks:
- Args:
- distance (integer):
the number of pixels to expand the masks by
- image_source (string or Path):
the file path to a folder containing the cell masks (as tiff files) to expand
- output_directory (string or Path):
the file path to a folder containing the cell masks (as tiff files) to expand
- Inputs / Outputs:
- Inputs:
reads every file in image_source folder (expecting .tiff format for all)
- Outputs:
writes a (.ome).tiff into the output_directory folder for each file read-in from image_source The filenames in the image_source folder as preserved in the output_directory, so if image_source == output_directory then the original masks will be overwritten.
- class palmettobug.ImageProcessing.ImageAnalysisClass.ImageAnalysis(directory: pathlib.Path | str | None, resolutions: list[float, float] = [1.0, 1.0], from_mcds: bool = True)
This handles Image Processing steps of PalmettoBUG, such as conversion from mcd’s and segmentation measurements
- Args:
- directory (str, Path, or None):
The directory to step up the image analysis / PalmettoBUg project inside of. Is expecting the directory to already exist & there to be .mcd or .tif / .tiff files in a /raw subfolder of directory. If None, then initiates an ImageAnalysis object without needing to set up the directory. This can be useful if you don’t need the /raw –> /images/img conversion step and you intend to manually set the input / output folder paths at each step.
- resolutions (list of float):
Default = [1.0, 1.0]. Represents the width of the pixels in [X, Y] directions in micrometers.
- from_mcds (bool):
If True, assumes that there will be MCD files in /raw. If False, presumes there are .tif/.tiff files in /raw.
- Key Attributes:
- directory (str):
the path to a folder containing a /raw/ subfolder where the MCD or TIFF files are
- directory_object (DirSetup):
this attribute is a sub-class from Utils/SharedClasses.py module. it coordinates directories of the typical PalmettoBUG project –
Key Subattributes
(self.directory_object).main == self.directory >>> The highest-level directory of the project
raw_dir == {directory}/raw >>> the folder containing the MCD or TIFF files of raw data
- img_dir == {directory}/images >>> the folder containing sub-folders of images (such as the img_dir/img sub-folde, which contains
the initial images directly converted from the raw_dir)
- masks_dir == {directory}/masks >>> the folder containing sub-folders of cell masks (such as the masks_dir/deepcell_masks sub-folder,
which contains the cell masks created by deepcell, before any modifications / expansions are performed on those masks.)
- classy_masks_dir == {directory}/classy_masks >>> the folder containing sub-folders of classy cell masks. Each subfolder is named
by convention using the pixel classifier + cell mask pair that the clasy masks were derived from.
px_classifiers_dir == {directory}/Pixel_Classification >>> the folder containing sub-folders of pixel classifiers
Analyses_dir == {directory}/Analyses >>> the folder containing sub-folders of Analysis directories.
logs == {directory}/Logs –> the folder containing the .log files generated by the GUI
- from_mcds (boolean):
whether the files in directory/raw are MCD files (True), or are TIFF files (False)
- resolutions (list[float, float]):
the X and Y resolutions of the images, in micrometers / pixel
- panel (pandas dataframe):
This is a pandas dataframe read-in from & written to directory/panel.csv This is a steinbock-style panel (with changes), with four columns = “name”,”antigen”,”keep”,”segmentation”
- metadata (pandas dataframe):
This is the dataframe containing a CATALYST-style metadata file. It is really intended for the Analysis portion of the program and is not used in image processing, however this class produces a preliminary version of this dataframe as a part of the transition from image processing –> analysis
It has four columns –
“file_name” == the filenames of the .fcs files in the analysis
“sample_id” == numbers to identify each filename quickly (zero-indexed)
“patient_id” == a secondary grouping / covariate / batch
“condition” == the independent variable / treatment vs. control grouping
- Analysis_panel (pandas dataframe):
This is the dataframe containing a CATALYST-style panel file. It is really intended for the Analysis portion of the program and is not used in image processing, however this class produces a preliminary version of this dataframe as a part of the transition from image processing –> analysis
It has three columns:
“fcs_colname” == the name of the marker in the .fcs files. when coming straight from solution-mode fcs files, these names can be non-straightforward or confusing (often metal names. Ex: Ce140Di) When produced from an imaging experiment the fcs names are usually identical to the “antigen” names:
“antigen” == the name of the marker to use in analysis plots, usually its straightforward, biological name (ex: CD4)
“marker_class” == ‘type’,’state’, or ‘none’ – used as in CATALYST-style workflow to determine how markers are used.
- from_mcds = True
- resolutions = [1.0, 1.0]
- metadata
- Analysis_panel
- _panel_setup() None
This will either read in the panel.csv file in the top-level project folder, or failing that will attempt to generate a panel file automatically.
- Note:
– This method depends on the self.from_mcds attribute to know whether mcds or tiffs are in the /raw folder
– Any automatically generated panel file will have an entirely blank ‘segmentation’ column. This requires editing before segmentation can be performed using deepcell or cellpose
– additionally, the automatically generated ‘keep’ column may not accurately reflect what you want, although it often does.
- panel_write() None
This method writes the self.panel dataframe to the disk at the expected location for future re-read (panel.csv in the top-level folder of the project)
- raw_to_img(hpf: int = 50, input_directory: str | pathlib.Path | None = None, output_directory: str | pathlib.Path | None = None) None
This method converts/moves files from the /raw folder –> /images/img folder. It always exports in .ome.tiff format with two transformations of the images in the raw files:
channels with ‘keep’ == 0 in the panel file will be dropped from the exported .ome.tiffs
hot pixel filtering will be performed before exporting to the /images/img folder if hpf > 0
It depends on self.from_mcds to know whether to expect MCD or TIFF files in the /raw folder.
- Args:
- hpf (int >= 0):
an integer denoting the threshold used for steinbock-style hot pixel filtering. This means that pixels that are brighter than each of their surrounding neighbor pixels by more than the inputted threshold will have their values reduced to match the value of their brightest neighbor pixel. So lower thresholds will more aggressively filter “hot” / bright pixels, while higher thresholds will filter less. The default (50) matches the default value in steinbock. ** If hpf == 0, no hot pixel filtering will occur. **
- input_directory (str, Path, or None):
a path to the folder containing the .mcd or .tiff files to be converted and hot-pixel filtered. Assumes that the folder chosen ONLY contains files (no sub-folders) and that all of those files are of the appropriate format.
- output_directory (str, Path, or None):
A path to a folder to write the .ome.tiff files to. If None, then defaults to the self.directory.main + “/images/img/” subfolder
- Returns:
None: (its output is in writing to the disk, not returning a value)
- instanseg_segmentation(re_do: bool = False, input_img_folder: pathlib.Path | str | None = None, single_image: pathlib.Path | str | None = None, output_mask_folder: pathlib.Path | str | None = None, channel_slice: None | numpy.array = None, merge_channels: bool = False, pixel_size: float | None = None, target: str = 'cells', mean_threshold: float = 0.0, model: str = 'fluorescence_nuclei_and_cells') None
Instanseg is an open-source (no non-commercial issues) deep-learning segmentation algorithm: https://github.com/instanseg/instanseg/tree/main
Channels are scaled by a min_max transformation before being used (and before being merged together, if that is chosen).
- Args:
- input_img_folder (str, Path, or None):
The path to a folder containing the images to segment. If None, defaults to f”{self.directory_object.img_dir}/img”
- output_mask_folder (str, Path, or None):
The path to a folder where you want the segmentation masks to be written to. If None, defaults to f”{self.directory_object.masks_dir}/instanseg_masks”
- single_image (str, Path, or None):
If not None (and not the empty string “”), this parameter provides the name or path of a single image in the input_img_folder to segment.
- channel_slice (integer numpy array or None):
If provided, will be used to slice each image array to subset the channels provided to the instanseg model. The length of this array must be the same as the number of channels in the images. Specifically, the channels in the image that will be used will be: image[channel_slice > 0] If None, all channels in all images are used as independent channels.
- merge_channels (boolean):
IF channel_slice is provided, this determines whether the selected channels are merged into two (cytoplasmic / nuclear – True) or left as separate channels (False, default).
- pixel_size (float or None):
resolution of the pixels in the images. If None, defaults to using self.resolutions (self.resolutions[0] == self.resolutions[1] must be true) Provided to the pixel_size argument of the instanseg model
- target (str):
“cells”, “nuclei”, or “all_outputs”. Whether to try to segment whole cells, only the nuclei, or both. Provided to the target argument of the instanseg model
- mean_threshold (float):
Higher values decrease the number of cells (higher threshold for identifying a cell) while lower number should increase the number of detected cells
- model (str):
what pre-trained instanseg model to use. Currently instanseg only offeres two models (fluoresence-based, the default, and a H&E based model) More options will hopefully open up as this segmentation model is developed. Theoretically, there should be a way to allow custom-trained models to loaded as well, which could be quite nice.
## example test script – results so far: it works in that it runs, but the results are very poor compared to deepcell ## maybe instanseg needs a dedicated IMC model, or needs a larger training set (like TissueNet, but that particular dataset would create ## license issues)) import palmettobug proj_dir = f”{my_computer_path}/Example_IMC” image_object = palmettobug.ImageAnalysis(proj_dir, resolutions = [1.0,1.0]) panel_keep_only = image_object.panel[image_object.panel[‘keep’] == 1] nuclei_slice = panel_keep_only[‘segmentation’] == “Nuclei” image_object.instanseg_segmentation(channel_slice = nuclei_slice, target = “nuclei”, mean_threshold = -1.0)
- mask_intersection_difference(masks_folder1: str | pathlib.Path, masks_folder2: str | pathlib.Path, kind: str = 'intersection1', object_threshold: int = 1, pixel_threshold: int = 1, re_order: bool = True, output_folder: None | str | pathlib.Path = None)
Provide two folders of masks, and derive a third folder of masks from them transformed in some way. Masks are dropped as a whole (not pixel-wise), and there are a limited set of possible transformations:
- intersection1 (one-way) – This keeps the masks from the first folder of masks, but only the masks that overlap with sufficient masks from folder2
No masks from folder2 carry over to the output folder
- intersection2 (two-way) – This keeps masks from both folders, as long as they overlap sufficiently. HOWEVER, masks from folder1 take precedence
As in, where overlap exists only mask1 values will be carried over first and mask2 values will only end up in the output after that where the output has values of 0 (which is to say, only in regions outside the remaining masks from mask1) Additionally, masks from the second folder are given a value = mask2 + max(mask1) in the output so that they will remain distinct from folder1-derived masks.
difference1 (one-way) – This keeps masks from folder1 only if a sufficient number of masks from folder2 do NOT overlap with them
- difference2 (two-way) – This keeps masks from both folders, but only if they do not overlap with sufficient masks from the opposite folder.
HOWEVER: Masks from the first folder take precedence over mask from the second! As in, the masks from folder1 which are kept in the transformation are carried over into the output first, and after that the masks from folder2, but only into pixels with value 0 in the output. This precedence should only matter if the thresholds are increased above the defaults of 1, as otherwise there should be no overlap at all between the saved masks from the two folders. Additionally, masks from the second folder are given a value = mask2 + max(mask1) in the output so that they will remain distinct from folder1-derived masks.
- an overlapping mask is determined by the pixel_threshold value – a mask from folder 2 is considered to overlap with a mask from folder 1 if the number of overlapping
pixels between the two is greater than or equal to the pixel_threshold value.
- ‘sufficient masks’ is determined by the object threshold (default = 1, as in, just 1 overlapping mask form folder2 within a mask from folder 1 means
triggers the transformation)
Together, this should allow this function to be used to do things like only keeping cell masks within a particular region of the tissue or only keeping tissue regions with sufficient number of cell masks inside them, etc. Or, by chaining this operation together, only keeping cells within particular region of tissue, where those regions of tissue have sufficient numbers of cells (of a particular cell type, even, if using classy masks to further sophisticate things). The (possible) addition of this function was inspired by analyses performed in the following paper using pancreatic islets:
Damond, Nicolas et al. “A Map of Human Type 1 Diabetes Progression by Imaging Mass Cytometry.” Cell metabolism vol. 29,3 (2019): 755-768.e5. doi:10.1016/j.cmet.2018.11.014
The publicly-available data from this paper is also planned to be analyzed in PalmettoBUG, in order to compare the effectiveness of PalmettoBUG at replicating prior work.
- Args:
- masks_folder1 / 2 (string, Path):
paths to two folders of masks – as in, each folder is expected to contain single-channel, integer-valued tiff files where each integer represents a unique cell (or other object). There must be files in each folder with matching file names – only these can be processed! Note that the order of the folders (as in, which is masks_folder1 vs masks_folder2) is very important for some transformations!
- kind (string):
One of [‘intersection1’, ‘intersection2’, ‘difference1’, or ‘difference2’]. Determines how the maasks are transformed. See description above for details. Note that when kind = ‘difference2’, the object/pixel threshold comparisons are also utilized in the reverse (from mask folder 2 –> 1)
- object_threshold (integer):
when determining whether a mask from folder1 overlaps with masks from folder2, this determines how many ‘overlapping’ objects inside it are sufficient to trigger keeping / discarding the mask. The default is 1, meaning that even a single overlapping mask is sufficient to trigger the transformation.
- pixel_threshold (integer):
when determing whether a mask from folder2 overlaps with a mask from folder1, this determines how many pixels of mask2 is sufficient to consider it overlapping. When == 1 (default), this means that even a single pixel of overlap will count mask2 as an object inside mask1. The total count of such overlapping mask2 objects inside mask1 are then compared to the object_threshold to determine whether to keep / discard mask1 from the output.
- re_order (boolean):
Whether to re-index the masks, starting from 1 and continuously increasing in increments of 1, so that there are no gaps / discontinuities in the values. Default = True, which re-indexes to start from 1 etc. However, if you want to preserve the original mask values (of mask1 only), so that they can be matched to the original masks, set this parameter == False. Because of how two-way methods work, the original values of mask folder2 are not preserved regardless of this parameter.
- output_folder (string, Path, or None):
The path to a file folder where the output, transformed masks can be written. If None (default), then the file folder name is automatically derived from the names of folder1 and folder2 (specifically: {self.directory_object.masks_dir}/{folder1}_{folder2} ). This folder automatically inside the masks directory of the PalmettoBUG project folder. If provided, should be a FULL path to a create-able folder where the masks will be written.
- Returns:
None (does, however, read & write .tiff files)
- _mask_bool(mask1: numpy.ndarray[int], mask2: numpy.ndarray[int], kind: str = 'intersection1', object_threshold: int = 1, pixel_threshold: int = 1, re_order: bool = True) numpy.ndarray[int]
helper for self.boolean_mask_transform, executing the operation on a single pair of masks
- make_segmentation_measurements(input_img_folder: pathlib.Path | str, input_mask_folder: pathlib.Path | str, output_intensities_folder: pathlib.Path | str | None = None, output_regions_folder: pathlib.Path | str | None = None, statistic: str = 'mean', re_do: bool = False, advanced_regionprops: bool = False) None
This method measures statistics and regionproperties from cell masks + images, and writes these as intensity and regionprops csv files in an output folder. This output folder is structured such that a PalmettoBUG-style analysis can easily be launched from it.
It is derived & and relies upon steinbock region_measurements functions (and through them, skimage).
- Args:
- input_img_folder (Path, str):
the file path to the folder containing the images to be used for measuring statistics / intensities
- input_mask_folder (Path string):
the file path to the folder contianing the masks to be used for measuring both stats / intensities AND region properties (the region properties depend only on the shape of the masks, not of the channels of the matching images)
NOTE! – the input_img_folder and input_mask_folder are presumed to have the same number of files & these files share filenames / order. This is the default way that PalmettoBUG / isoSegDenoise exports these files, but be careful to make sure to change this to be the case if your data does not match this pattern!
- output_intensities_folder (Path, string, None):
the file path to the folder to export the intensity csv files (these csv files are effectively like fcs files with events [‘Object’] each with intensity measurements / statistics for each channel). If None, then the self.directory_object.intensities_dir will be used – this depends on having set up an analysis using the self.directory_object.make_analysis_dirs(analysis_name) method beforehand
- output_intensities_folder (Path, string, None):
the file path to the folder contianing the regionprops csv files for each mask. Like the intensities csv’s these are structured with measurements for each object/event/cell, but are measurements like area, perimeter, etc. If None, then will use the self.directory_object.regionprops_dir – this depends on calling the self.directory_object.make_analysis_dirs(analysis_name) method beforehand
- statistic (string):
The statistic to report for each cell/object for each channel in the instensity csv files. One of [“mean”,”median”,”min”,”max”,”sum”,”std”,”var”]. Default is “mean”, and you will rarely need any of the other options.
- re_do (boolean):
Determines whether to check if each intensities/regionprops csv has already been generated (by matching the file name) and ONLY export NEW csv files (if = True). Alternatively, export every csv file regardless of whether or not the export folder already contains identically named files (if = False).
Consider re_do = True if you are adding new files to a large existing project and don’t want the old files to be redone or are generating advanced regionprops (saves time),
otherwise re_do = False is frequently better as writing each file without advanced regionprops is not a very long process & ensures consistency at this step.
- advanced_regionprops (boolean):
If True, will calculate a few ‘advanced’ region properties, like –> [number of branch points, tortuosity, etc…] of the masks. This is a slow process so the default advanced_regionprops = False is preferred unless these additional region properties are greatly desired.
WARNING!! – This option is currently broken / unreliable (algorithms & packages used to derive these regionproperties appear to make errors in determining branching.)
- Returns:
None – (its output is in writing to the disk, not returning a value)
- _advanced_regionprops(input_mask_folder: pathlib.Path | str, output_regions_folder: pathlib.Path | str) None
Helper function for self.make_segmentation_measurements(). Calculates ‘advanced’ region properties: [n_slab, n_branch, tortuosity, cycles]
WARNING!! – Currently not accurate / functional (inaccurate, additional branches in simple tests). Error may propagate from NAVis library
- to_analysis(Analysis_tab=None, metadata_from_save: bool = False, gui_switch=None) None
This function prepares / sets up an Analysis folder, by converting intensity csv files to fcs files and generating preliminary / semi-empty metadata / panel pandas dataframes, which require editing before writing to the disk at the newly prepared self.Analysis_panel_dir and self.metadata_dir filepaths.
Depends on self.directory_object.make_analysis_dirs(analysis_name) being called first to set up the directory structure and direct the discovery of the intensity files which will be used to generate FCS files & the intial panel/metadata dataframes.
DOES NOT export the panel / metadata files to the disk, but returns them, along with the file paths where they are expected to be wrtten to, in the following order: (panel dataframe, metadata dataframe, panel path, metadata path)
- Args:
- Analysis_tab / metadata_from_save (Only for use inside GUI):
IGNORED outside of GUI. in the GUI they assist in coordinating the widgets & choosing to load the Analysis_panel/metadata files from the directory_object.Analyses_dir (if someone makes a second analysis in one project, instead of requiring a fresh panel/metadata set up each time a new analysis is made).
gui_switch (Boolean or None) – only needed if an error is making palmettobug think it is in the gui. Needed for a testing error
- _intense_to_fcs(input_intensity_directory: pathlib.Path | str | None = None, ouput_fcs_folder: pathlib.Path | str | None = None) None
Helper method for self.to_Analysis –> writes .fcs files from .csv files in the intensities folder.
When called with default arguments, depends on self.directory_object.make_analysis_dirs(analysis_name), however the input and output folders can be specified separately to allow its use in any context.
- Args:
- input_intensity_directory (Path, string, None):
the path to a folder where the intensity csv files are (exported by self.make_segmentation_measurements) If None, then a default path is presumed which requires a prior execution of the self.directory_object.make_analysis_dirs(analysis_name) method
- ouput_fcs_folder (Path, string, None):
the path to a folder where the FCS files will be written to, with the same behaviour as (input_intensity_directory) - if None, a default path self.directory_object.fcs_dir is presumed, etc.
- _initial_Analysis_panel() pandas.DataFrame
Helper method for self.to_Analysis generates an initial Analysis panel (marker_class column blank)
- _initial_metadata_file() pandas.DataFrame
Helper method for self.to_Analysis –> generate the initial metadata file (patient and condition columns blank)
- palmettobug.ImageProcessing.ImageAnalysisClass.setup_for_FCS(directory)
This sets up a folder for single-cell analysis using the CATALYST-derived module of PalmettoBUG.
Can be used for a solution-mode experiment (direct from FCS files) or as part of the set up when transitioning from image processing to single-cell analysis.
- Args:
- directory (str):
The directory to set up from single-cell analysis
- Returns:
Analysis_panel (a pandas dataframe of the initially generated Analysis_panel file, needs the marker_class column to be filled in by the user)
Analysis_panel_dir (a string, the path to where the Analysis_panel should be saved on the disk once it has been completed by the user)
metadata (a pandas dataframe of the initially generated metadata file, needs the patient_id and condition columns to be filled in by the user)
metadata_dir (a string, the path to where the metadata should be saved on the disk once it has been completed by the user)