Writing good code#

Writing readable code#

Technically, python allows us to write code like this.

a=5;b=3;c=8;d=(a+b)/c;print("Yin" if d==5 else "Yang")
Yang

However, for readability, it is recommended to write individual statements in individual lines. Also put empty lines between sections and introduce comments to explain why things are done.

# initialize program
a=5
b=3
c=8

# compute result before we can evaluate it
d=(a+b)/c

If you work with Jupyter notebooks, print out intermediate results to allow the reader to see what’s happening.

d
1.0

Consider writing spaces between variables, operators and numbers, because this is easier toreadthanthat,right?

d = (a + b) / c
d
1.0

Some people are ok with such short statements:

print("Yin" if d==5 else "Yang")
Yang

Others prefer to write code out.

if d == 5:
    print("Yin")
else:
    print("Yang")
Yang

Preventing code repetition#

Sometimes, we copy & paste like this multiple times to process images quickly.

import pyclesperanto_prototype as cle
image = cle.imread("../../data/BBBC007_batch/17P1_POS0013_D_1UL.tif")
labels = cle.voronoi_otsu_labeling(image, spot_sigma=3)
number_of_nuclei = labels.max()
number_of_nuclei
44.0
image = cle.imread("../../data/BBBC007_batch/20P1_POS0005_D_1UL.tif")
labels = cle.voronoi_otsu_labeling(image, spot_sigma=3)
number_of_nuclei = labels.max()
number_of_nuclei
41.0
image = cle.imread("../../data/BBBC007_batch/20P1_POS0007_D_1UL.tif")
labels = cle.voronoi_otsu_labeling(image, spot_sigma=3)
number_of_nuclei = labels.max()
number_of_nuclei
73.0

If we wanted to now see how changing the spot_sigma parameter above influences the result, we would need to change this value three times. When the code becomes even longer, it may happend that we forget to change it in one place.

For-loops instead of code repetition#

One way of preventing code-repetition are for-loops.

folder = "../../data/BBBC007_batch/"
files = ["17P1_POS0013_D_1UL.tif",
        "20P1_POS0005_D_1UL.tif",
        "20P1_POS0007_D_1UL.tif"]
for file in files:
    image = cle.imread(folder + file)
    labels = cle.voronoi_otsu_labeling(
                    image, 
                    spot_sigma=3)
    number_of_nuclei = labels.max()
    print(file, number_of_nuclei)
17P1_POS0013_D_1UL.tif 44.0
20P1_POS0005_D_1UL.tif 41.0
20P1_POS0007_D_1UL.tif 73.0

Functions instead of code-repetion#

We can gain even more flexibility by introducing so called helper functions, that help us by doing one dedicated thing, for example counting nuclei:

def count_nuclei(image, spot_sigma=3):
    labels = cle.voronoi_otsu_labeling(
                    image, 
                    spot_sigma=spot_sigma)
    number_of_nuclei = labels.max()
    
    return number_of_nuclei
count_nuclei(cle.imread(folder + files[0]))
44.0
count_nuclei(cle.imread(folder + files[1]))
41.0
count_nuclei(cle.imread(folder + files[2]))
73.0
count_nuclei(cle.imread(folder + files[2]), spot_sigma=5)
68.0