Analyzing Pixel Classification “As a Whole”

This notebook depends on the SupervisedClassifier notebook having been run first!!

[1]:
import os
import numpy as np
import pandas as pd

import palmettobug as pbug
The PalmettoBUG package is copyrighted 2024-2025 by the Medical University of South Carolina and licensed under the GPL-3 license.
It is free & open source software, can  be redistributed in compliance with the GPL3 license, and comes with absolutely no warranty.
In python, use palmettobug.print_license() to see the license, or use palmettobug.print_3rd_party_license_info() to print information
about the licenses and copyright of 3rd party software used in PalmettoBUG itself or in the creation of PalmettoBUG.
[2]:
pbug.__version__
[2]:
'0.2.11'

CHANGE The following directory to match an existing directory on your computer if you are testing this tutorial on your own machine!

[3]:
my_computer_path =  "C:/Users/Default/Desktop"  ## CHANGE This DIRECTORY to match an existing directory on your computer if you testing this tutorial on your own machine!

Setting up for a Whole-Class Analysis

This requires:

1). a pixel classification to have been run (usually a supervised classifier, but sometimes a merged / annotated unsupervised classifier could be used)

2). Region measurements must be taken from the classifier's predictions (treating them as if they are segmentation masks)

3). The set-up of Analysis_panel.csv and metadata.csv files, just like for standard single-cell / CATALYST-like analyses

In this case, requirements #1 and #3 will depend on other notebooks where those steps have already been done, but requirement #2 we do within this notebook, then load for whole-class analysis.

[4]:
''' Gather directories from which we'll read pixel class region properties '''

project_directory = f'{my_computer_path}/Example_IMC'

pixel_classifier_output = f'{project_directory}/Pixel_Classification/lumen_epithelia_laminapropria/classification_maps'

whole_class_directory = f'{project_directory}/Pixel_Classification/lumen_epithelia_laminapropria/Whole_class_analysis'
if not os.path.exists(whole_class_directory):
    os.mkdir(whole_class_directory)
[5]:
''' Make region measurements from pixel classifications '''

experiment = pbug.imc_entrypoint(project_directory, resolutions =  [1.0, 1.0], from_mcds = False)
analysis_folder_name = "Whole_class_analysis"
input_img_folder = experiment.directory_object.img_dir + "/img"
experiment.make_segmentation_measurements(input_img_folder,
                                          pixel_classifier_output,
                                          output_intensities_folder = whole_class_directory + "/intensities",
                                          output_regions_folder  = whole_class_directory + "/regionprops",
                                          statistic = 'mean',
                                          re_do = True)
CRC_1_ROI_001.ome intensities csv has been written!
CRC_1_ROI_002.ome intensities csv has been written!
CRC_2_ROI_001.ome intensities csv has been written!
CRC_2_ROI_002.ome intensities csv has been written!
CRC_2_ROI_003.ome intensities csv has been written!
CRC_2_ROI_004.ome intensities csv has been written!
CRC_3_ROI_001.ome intensities csv has been written!
CRC_3_ROI_002.ome intensities csv has been written!
CRC_3_ROI_003.ome intensities csv has been written!
CRC_3_ROI_004.ome intensities csv has been written!
CRC_1_ROI_001.ome regions csv has been written!
CRC_1_ROI_002.ome regions csv has been written!
CRC_2_ROI_001.ome regions csv has been written!
CRC_2_ROI_002.ome regions csv has been written!
CRC_2_ROI_003.ome regions csv has been written!
CRC_2_ROI_004.ome regions csv has been written!
CRC_3_ROI_001.ome regions csv has been written!
CRC_3_ROI_002.ome regions csv has been written!
CRC_3_ROI_003.ome regions csv has been written!
CRC_3_ROI_004.ome regions csv has been written!
[6]:
class_dict = {1: "lumen", 2: "epithelia", 3: "lamina_propria"}

seed_df = pd.DataFrame()
seed_df['class'] = [i for i in class_dict]
seed_df['labels'] = [class_dict[i] for i in class_dict]
zip_dict = {}
for i,ii in enumerate(seed_df['labels'].unique()):
    zip_dict[ii] = i

seed_df['merging'] = seed_df['labels'].replace(zip_dict)
seed_df


## Each of these dataframes has been created previously -- so in this case I will just retrieve them from the disc
classifier_df = seed_df
metadata = pd.read_csv(project_directory +  "/Analyses/metadata.csv")
panel = pd.read_csv(project_directory +  "/Analyses/Analysis_panel.csv")

metadata.to_csv(whole_class_directory + "/metadata.csv", index = False)
panel.to_csv(whole_class_directory + "/Analysis_panel.csv", index = False)

whole_class_analysis = pbug.WholeClassAnalysis(directory = whole_class_directory, classifier_df = classifier_df, metadata = metadata,
                             Analysis_panel = panel)

Now we can make plots

[7]:
'''Compare area of each pixel class between conditions:'''
fig = whole_class_analysis.plot_percent_areas()
fig
[7]:
../../_images/notebooks_PixelClassifiers_WholeClassAnalysis_10_0.png
[8]:
''' Look at the distribution of markers within a pixel class '''
facet_grid = whole_class_analysis.plot_distribution_exprs(unique_class = 'epithelia', plot_type = 'Violin')
facet_grid.figure
[8]:
../../_images/notebooks_PixelClassifiers_WholeClassAnalysis_11_0.png

Do Stats

The available statistics are very limited / basic. More advanced statistics should be done with a different software, and given that it is important to check the assumptions of the available statistical tests, it is generally best to do any statistical analysis w9ith at least the help of a differnet software.

[9]:
whole_class_analysis.whole_marker_exprs_ANOVA(marker_class = 'type', groupby_column = 'class', variable = 'condition', statistic = 'ANOVA', area = True)
[9]:
antigen class p_adj p_value F statistic avg SSA mean exprs SSA stdev avg TA mean exprs TA stdev
15 CD163 epithelia 2.330000e-08 7.780000e-09 609.000000 0.000481 0.000161 0.00570 0.000494
27 CD31 epithelia 9.460000e-07 3.150000e-07 237.000000 0.001830 0.000828 0.01110 0.001080
85 p-selectin lamina_propria 1.050000e-06 3.500000e-07 231.000000 0.003850 0.001200 0.01690 0.001530
23 CD206 lumen 1.810000e-06 6.050000e-07 200.000000 0.000653 0.000191 0.00336 0.000417
8 CD11b lumen 1.870000e-05 6.230000e-06 109.000000 0.001450 0.000872 0.00847 0.001280
... ... ... ... ... ... ... ... ... ...
50 CD8 lumen 9.660000e-01 9.660000e-01 0.001990 0.002090 0.001490 0.00205 0.000876
16 CD163 lamina_propria 9.690000e-01 9.690000e-01 0.001660 0.005430 0.004530 0.00552 0.000517
42 CD66b epithelia 9.690000e-01 9.690000e-01 0.001590 0.002170 0.002720 0.00223 0.001450
0 Beta-Catenin epithelia 9.760000e-01 9.760000e-01 0.000944 0.475000 0.113000 0.47200 0.168000
81 areas****** epithelia 9.960000e-01 9.960000e-01 0.000022 26.900000 8.210000 26.80000 6.600000

87 rows × 9 columns

[10]:
whole_class_analysis.plot_heatmap("p_adj")
[10]:
../../_images/notebooks_PixelClassifiers_WholeClassAnalysis_14_0.png

Or export the data in tabular form to examine in another software / package:

[11]:
to_export = whole_class_analysis.export_data(filename = None,           #Or specify a file path to write to, usch as:   whole_class_analysis.directory + "/my_data_export.csv",
                        subset_columns = None,
                        subset_types = None,
                        groupby_columns = None,
                        statistic= 'mean',
                        include_marker_class_row = False)   ## TODO: figure out csv reload with whole class analysis --> for now, not supported
to_export
C:\Users\benca\miniforge3\envs\main\lib\site-packages\anndata\_core\aligned_df.py:68: ImplicitModificationWarning: Transforming to str index.
  warnings.warn("Transforming to str index.", ImplicitModificationWarning)
[11]:
antigen aSMA p-selectin Vimentin CD14 CD31 CD16 Pan-Keratin CD11b CD163 CD45 ... Seg2 Seg3 index sample_id file_name patient_id condition Object class areas
0 0.046404 0.002377 0.021375 0.077686 0.001858 0.003592 0.373355 0.003115 0.000352 0.014310 ... 0.105902 0.168999 0 0 CRC_1_ROI_001.ome.fcs 7139 SSA 1 lumen 16.497600
1 0.279869 0.004667 0.038276 0.012763 0.003151 0.006478 0.643430 0.007177 0.000741 0.037614 ... 0.218496 0.217236 1 0 CRC_1_ROI_001.ome.fcs 7139 SSA 2 epithelia 36.050400
2 0.583634 0.005288 0.231591 0.038185 0.015873 0.008793 0.159639 0.010919 0.002667 0.175283 ... 0.200154 0.181208 2 0 CRC_1_ROI_001.ome.fcs 7139 SSA 3 lamina_propria 47.452000
3 0.052761 0.001284 0.016471 0.055562 0.001277 0.001374 0.048797 0.001126 0.000179 0.014350 ... 0.067809 0.152127 3 1 CRC_1_ROI_002.ome.fcs 7139 SSA 1 lumen 35.531467
4 0.441734 0.019529 0.028416 0.005586 0.002109 0.003486 0.095743 0.003626 0.000498 0.020471 ... 0.148266 0.181678 4 1 CRC_1_ROI_002.ome.fcs 7139 SSA 2 epithelia 15.908267
5 0.461414 0.003406 0.134013 0.023865 0.008549 0.005665 0.036053 0.004593 0.002851 0.090782 ... 0.228512 0.158975 5 1 CRC_1_ROI_002.ome.fcs 7139 SSA 3 lamina_propria 48.560267
6 0.043961 0.001348 0.039967 0.017418 0.001145 0.001152 0.063610 0.001428 0.000256 0.030570 ... 0.074013 0.166255 6 2 CRC_2_ROI_001.ome.fcs 7139 SSA 1 lumen 40.148800
7 0.050636 0.002190 0.015143 0.004244 0.001938 0.002836 0.239402 0.003481 0.000497 0.020262 ... 0.093077 0.189527 7 2 CRC_2_ROI_001.ome.fcs 7139 SSA 2 epithelia 36.967600
8 0.385122 0.003522 0.240166 0.021005 0.011558 0.004695 0.016083 0.007222 0.003367 0.160490 ... 0.135513 0.174451 8 2 CRC_2_ROI_001.ome.fcs 7139 SSA 3 lamina_propria 22.883600
9 0.048720 0.001244 0.017306 0.027874 0.000866 0.001455 0.084637 0.000899 0.000146 0.005761 ... 0.128837 0.157224 9 3 CRC_2_ROI_002.ome.fcs 7139 SSA 1 lumen 44.958000
10 0.238822 0.002845 0.017037 0.005089 0.001525 0.003130 0.157704 0.002277 0.000392 0.008053 ... 0.175399 0.180829 10 3 CRC_2_ROI_002.ome.fcs 7139 SSA 2 epithelia 22.159600
11 0.531417 0.005083 0.291689 0.020345 0.005762 0.005054 0.044761 0.004031 0.001856 0.093584 ... 0.253888 0.167786 11 3 CRC_2_ROI_002.ome.fcs 7139 SSA 3 lamina_propria 32.882400
12 0.035091 0.001602 0.027311 0.082346 0.001521 0.001601 0.082200 0.001488 0.000326 0.026056 ... 0.047149 0.152558 12 4 CRC_2_ROI_003.ome.fcs 7139 SSA 1 lumen 7.479200
13 0.110517 0.002089 0.033115 0.007243 0.001643 0.003004 0.138882 0.004171 0.000505 0.026921 ... 0.157469 0.205587 13 4 CRC_2_ROI_003.ome.fcs 7139 SSA 2 epithelia 25.846400
14 0.338910 0.003757 0.216403 0.024321 0.008768 0.011529 0.010334 0.009493 0.008544 0.156488 ... 0.262179 0.173224 14 4 CRC_2_ROI_003.ome.fcs 7139 SSA 3 lamina_propria 66.674400
15 0.031635 0.006760 0.021256 1.680096 0.053469 0.009906 0.005348 0.000664 0.001362 0.003080 ... 0.016429 0.148124 15 5 CRC_2_ROI_004.ome.fcs 7139 SSA 1 lumen 4.778909
16 0.183516 0.001641 0.016439 0.003520 0.000621 0.000745 0.025288 0.000837 0.000252 0.002806 ... 0.047211 0.177667 16 5 CRC_2_ROI_004.ome.fcs 7139 SSA 2 epithelia 24.179636
17 0.217762 0.002035 0.193029 0.015542 0.006711 0.002814 0.003055 0.004390 0.013288 0.042991 ... 0.038650 0.154528 17 5 CRC_2_ROI_004.ome.fcs 7139 SSA 3 lamina_propria 71.041455
18 0.062293 0.016413 0.100151 0.042670 0.007151 0.009943 0.107857 0.009370 0.003144 0.177840 ... 0.084772 0.163744 18 6 CRC_3_ROI_001.ome.fcs 7139 TA 1 lumen 15.121000
19 0.191357 0.019775 0.057836 0.018934 0.012637 0.015682 0.242961 0.015912 0.005724 0.105703 ... 0.103431 0.200553 19 6 CRC_3_ROI_001.ome.fcs 7139 TA 2 epithelia 34.485600
20 0.281676 0.018888 0.201009 0.027490 0.015082 0.020664 0.100855 0.017962 0.005775 0.407615 ... 0.183162 0.180404 20 6 CRC_3_ROI_001.ome.fcs 7139 TA 3 lamina_propria 50.393400
21 0.061697 0.015720 0.084369 0.089420 0.006197 0.009044 0.124590 0.009496 0.003162 0.076874 ... 0.106464 0.143011 21 7 CRC_3_ROI_002.ome.fcs 7139 TA 1 lumen 12.536600
22 0.167929 0.018500 0.051282 0.016637 0.010217 0.013284 0.239551 0.012887 0.005303 0.057870 ... 0.092356 0.164743 22 7 CRC_3_ROI_002.ome.fcs 7139 TA 2 epithelia 29.006200
23 0.208419 0.015966 0.149385 0.024263 0.013647 0.018055 0.104513 0.016503 0.005405 0.226643 ... 0.169895 0.153509 23 7 CRC_3_ROI_002.ome.fcs 7139 TA 3 lamina_propria 58.457200
24 0.053290 0.013046 0.022435 0.080215 0.005233 0.007236 0.041152 0.006740 0.002285 0.012031 ... 0.045199 0.137282 24 8 CRC_3_ROI_003.ome.fcs 7139 TA 1 lumen 16.764000
25 0.207609 0.015706 0.025147 0.013484 0.010499 0.012301 0.088116 0.010148 0.005396 0.020136 ... 0.088967 0.151050 25 8 CRC_3_ROI_003.ome.fcs 7139 TA 2 epithelia 24.993600
26 0.318935 0.017284 0.279070 0.029856 0.020118 0.016477 0.039863 0.013732 0.006054 0.100555 ... 0.160039 0.145882 26 8 CRC_3_ROI_003.ome.fcs 7139 TA 3 lamina_propria 58.242400
27 0.050464 0.015304 0.030541 0.016861 0.005928 0.008065 0.062523 0.008266 0.003270 0.038459 ... 0.043146 0.134916 27 9 CRC_3_ROI_004.ome.fcs 7139 TA 1 lumen 26.593600
28 0.114999 0.019065 0.041749 0.016181 0.010985 0.012104 0.159120 0.011640 0.006394 0.057640 ... 0.052795 0.141570 28 9 CRC_3_ROI_004.ome.fcs 7139 TA 2 epithelia 18.830600
29 0.230477 0.015477 0.069437 0.018115 0.013465 0.013979 0.053264 0.014817 0.004859 0.148455 ... 0.101144 0.142696 29 9 CRC_3_ROI_004.ome.fcs 7139 TA 3 lamina_propria 54.575800

30 rows × 42 columns

[ ]: