Note: Original analysis run using jupyter notebooks, transcribed for website presentation.

import czifile
from skimage import io
import numpy as np
import matplotlib.pyplot as plt
import napari
from glob import glob
from os import path
import scipy
import pandas as pd
from skimage.filters import threshold_otsu, threshold_multiotsu
from scipy import ndimage
#function for reading czi files
def read_czi(file_path):
    img = czifile.imread(file_path)
    img = img[0,0,:,0,0,:,:,0] # remove extra dimensions
    return (img)
img_files = sorted(glob("../data/*.czi"))
file_names = [path.basename(a) for a in img_files]

print(file_names)
#generate sample matrix to check that conditions correctly match

condition = ["IWR", "IWR", "IWR", "PBS", "PBS", "PBS"]
sample_matrix = pd.DataFrame({'file':file_names, 'condition': condition})
sample_matrix
#load all image files and annotation files and check that dimensions and indicies are correct

img_list = []
labels_list = []

for file_idx, name in enumerate(img_files):
    print(file_idx)
    
    labels_file = 'labels_' + str(file_idx) + ".tif"
    print(labels_file)
    labels = io.imread(labels_file)
    print(labels.shape)
    labels_list.append(labels)
    
    print(name)
    print(path.exists(name))
    img = read_czi(name)
    print(img.shape)
    img_list.append(img)
#function for thresholding using standard otsu method afer gaussian filter.
def gauss_and_thresh(image, sigma = 5):
    image = ndimage.gaussian_filter(image, sigma)
    thresh = threshold_otsu(image)
    print(thresh)
    return (image > thresh)

#function for thresholding using multi-otsu after gaussian filter.
def gauss_and_multithresh(image, sigma = 5):
    image = ndimage.gaussian_filter(image, sigma)
    thresh = threshold_multiotsu(image)
    print(thresh)
    return (image > thresh[1])

#define variables to store output
beads_dist_map = []
epcam_segs = []
ltl_segs = []
glom_segs = []
prox_segs = []
dist_segs = []
beads_lines = []

#metrics for plotting
rad = [] #beads radius
gir = [] #gloms in radius
lir = [] #ltl in radius
eir = [] #epcam in radius
prir = [] #prox in radius
dtir = [] #distal in radius
glepir = [] #glom + epcam in radius

for labels, img in zip(labels_list, img_list):
    
    #define distance from beads using distance transform
    
    binary_beads = labels > 0
    binary_beads = 1 - binary_beads.astype('int')
    beads_dist = scipy.ndimage.morphology.distance_transform_edt(binary_beads)
    beads_dist_map.append(beads_dist)
    
    #segmentation
    
    glom = gauss_and_thresh(img[0,:,:], sigma = 5)
    glom_segs.append(glom)
    
    ltl = gauss_and_multithresh(img[2,:,:], sigma = 5)
    ltl_segs.append(ltl)
    
    epcam = gauss_and_multithresh(img[3,:,:], sigma = 5)
    epcam_segs.append(epcam)
    
    #define radius
    beads_radius = beads_dist < 200
    rad.append(np.sum(beads_radius))
    
    #define line used for generating visualisation
    beads_line = (beads_dist > 195) & (beads_dist < 205)
    beads_lines.append(beads_line)
    
    #find segmented pixels in radius
    glom_in_radius = glom & beads_radius
    gir.append(np.sum(glom_in_radius))
    
    ltl_in_radius = ltl & beads_radius
    lir.append(np.sum(ltl_in_radius))
    
    epcam_in_radius = epcam & beads_radius
    eir.append(np.sum(epcam_in_radius))
    
    glom_plus_epcam = epcam_in_radius + glom_in_radius
    glepir.append(np.sum(glom_plus_epcam))
    
    proximal = ltl & epcam
    prox_segs.append(proximal)
    prox_in_radius = proximal & beads_radius
    prir.append(np.sum(prox_in_radius))
    
    distal = np.invert(ltl) & epcam
    dist_segs.append(distal)
    dist_in_radius = distal & beads_radius
    dtir.append(np.sum(dist_in_radius))
    
    print("total pixels in radius: {}".format(np.sum(beads_radius)))
    
    print("gloms in radius: {}".format(np.sum(glom_in_radius)))
    print("glom %: {}".format(np.sum(glom_in_radius) / np.sum(beads_radius)))
    
    print("ltl in radius: {}".format(np.sum(ltl_in_radius)))
    print("ltl %: {}".format(np.sum(ltl_in_radius) / np.sum(beads_radius)))
    
    print("epcam in radius: {}".format(np.sum(epcam_in_radius)))
    print("epcam %: {}".format(np.sum(epcam_in_radius) / np.sum(beads_radius)))
    
    print("total proximal pixels in radius: {}".format(np.sum(prox_in_radius)))
    print("proximal %: {}".format(np.sum(prox_in_radius) / np.sum(beads_radius)))
    
    print("total distal pixels in radius: {}".format(np.sum(dist_in_radius)))
    print("distal %: {}".format(np.sum(dist_in_radius) / np.sum(beads_radius)))
all_data = pd.concat([sample_matrix, 
           pd.Series(data = rad, name = "bead_radius"),
           pd.Series(data = gir, name = "gloms_in_radius"),
           pd.Series(data = lir, name = "ltl_in_radius"),
           pd.Series(data = eir, name = "epcam_in_radius"),
           pd.Series(data = prir, name = "proximal_in_radius"),
           pd.Series(data = dtir, name = "distal_in_radius"), 
            pd.Series(data = glepir, name = "tissue_in_radius")], axis = 1)

all_data
#save all output to csv file

all_data.to_csv("all_data_output.csv")
#code for generating plots

fig, axs = plt.subplots(1, 7, figsize=(14, 3))

cond = all_data['condition']
total_bead_area = all_data["bead_radius"] / 1000000
total_tissue = all_data["tissue_in_radius"] / 1000000
dist = all_data["distal_in_radius"] / all_data["tissue_in_radius"] * 100
prox = all_data["proximal_in_radius"] / all_data["tissue_in_radius"] * 100
glom = all_data["gloms_in_radius"] / all_data["tissue_in_radius"] * 100
ltl = all_data["ltl_in_radius"] / all_data["tissue_in_radius"] * 100
epcam = all_data["epcam_in_radius"] / all_data["tissue_in_radius"] * 100

axs[0].plot(cond, total_bead_area, marker='o', linestyle='', ms=12, alpha = 0.5)
axs[0].margins(0.5,0.2)
axs[0].set_ylim([0,2.5])
axs[0].invert_xaxis()
axs[0].set_title("Total area (10^6 pix)")

axs[1].plot(cond, total_tissue, marker='o', linestyle='', ms=12, alpha = 0.5)
axs[1].margins(0.5,0.2)
axs[1].set_ylim([0,2.5])
axs[1].invert_xaxis()
axs[1].set_title("Nephron area (10^6 pix)")

axs[2].plot(cond, glom, marker='o', linestyle='', ms=12, alpha=0.5)
axs[2].margins(0.5,0.2)
axs[2].set_ylim([0,100])
axs[2].invert_xaxis()
axs[2].set_title("% NPHS1")

axs[3].plot(cond, epcam, marker='o', linestyle='', ms=12, alpha=0.5)
axs[3].margins(0.5,0.2)
axs[3].set_ylim([0,30])
axs[3].invert_xaxis()
axs[3].set_title("% EPCAM")

axs[4].plot(cond, ltl, marker='o', linestyle='', ms=12, alpha=0.5)
axs[4].margins(0.5,0.2)
axs[4].set_ylim([0,30])
axs[4].invert_xaxis()
axs[4].set_title("% LTL")

axs[5].plot(cond, dist, marker='o', linestyle='', ms=12, alpha=0.5)
axs[5].margins(0.5,0.2)
axs[5].set_ylim([0,30])
axs[5].invert_xaxis()
axs[5].set_title("% LTL- EPCAM+")

axs[6].plot(cond, prox, marker='o', linestyle='', ms=12, alpha = 0.5)
axs[6].margins(0.5,0.2)
axs[6].set_ylim([0,30])
axs[6].invert_xaxis()
axs[6].set_title("% LTL+ EPCAM+")


fig.tight_layout()
plt.show()
fig.savefig("finalplots.tif", dpi=300)
#code for loading all segmented images into napari for visualisation.

viewer = napari.view_image(np.array(img_list), channel_axis=1, colormap=["gray","yellow","green","blue"])
labels_layer = viewer.add_labels(np.array(labels_list), name="segmentation")
dist_map = viewer.add_image(np.array(beads_dist_map), name="dist", colormap="viridis", blending = 'additive')
glom_layer = viewer.add_image(np.array(glom_segs), name="glom", colormap="red", blending = 'additive')
epcam_layer = viewer.add_image(np.array(epcam_segs), name="epcam", colormap="red", blending = 'additive')
prox_layer = viewer.add_image(np.array(ltl_segs), name="ltl", colormap="green", blending = 'additive')
#dist_layer = viewer.add_image(np.array(dist_segs), name="dist", blending = 'additive')
radius_layer = viewer.add_image(np.array(beads_lines), name="radius", blending = "additive")
napari.run()
#code for calculating mean values

norm_values = all_data["tissue_in_radius"]
df = all_data[["gloms_in_radius","ltl_in_radius","epcam_in_radius","proximal_in_radius","distal_in_radius"]] 
df_norm = df.div(norm_values, axis=0) * 100
df_norm = pd.concat([all_data["condition"], df_norm], axis=1)

print(df_norm)
df_norm.groupby("condition").mean()
#generate separate dataframe for each condition to allow t tests below.

pbs = df_norm[df_norm['condition'] == 'PBS']
iwr = df_norm[df_norm['condition'] == 'IWR']
#performing t-tests

print("% Nphs1: {}".format(scipy.stats.ttest_ind(pbs['gloms_in_radius'],iwr['gloms_in_radius'])))

print("% LTL: {}".format(scipy.stats.ttest_ind(pbs['ltl_in_radius'],iwr['ltl_in_radius'])))

print("% Epcam: {}".format(scipy.stats.ttest_ind(pbs['epcam_in_radius'],iwr['epcam_in_radius'])))

print("% LTL+ Epcam+: {}".format(scipy.stats.ttest_ind(pbs['proximal_in_radius'],iwr['proximal_in_radius'])))

print("% LTL- Epcam+: {}".format(scipy.stats.ttest_ind(pbs['distal_in_radius'],iwr['distal_in_radius'])))
#t tests for raw values

print(all_data)

pbs_raw = all_data[all_data['condition'] == 'PBS']
iwr_raw = all_data[all_data['condition'] == 'IWR']

print("total bead area: {}".format(scipy.stats.ttest_ind(pbs_raw['bead_radius'],iwr_raw['bead_radius'])))
print("total tissue area: {}".format(scipy.stats.ttest_ind(pbs_raw['tissue_in_radius'],iwr_raw['tissue_in_radius'])))

sessionInfo()