Python Project Structure
Our default Python template has a lot of folders and files. In this section you'll learn the purpose of each file and how it is interrelated with the APEER architecture.
Before we change anything in the source code, we should understand what the different files within your module are used for.

.git and .gitignore

These files keep track of your git related activities. Ignore these as you will not edit or use them directly.

input folder

This folder contains a test OME-TIFF image. You can place your own input files here.

output folder

This folder contains a json file that you can ignore for now. When you run your code as a local Docker container, the output will be saved into this folder.

This is the entry python file for the Docker. This file calls the main file with Python code and executes it using the parameters defined here. You will make minor edits to this file later.
Please pay attention to the first line from apeer_der_kit import adk. Our APEER Python SDK aka. apeer-dev-kit (ADK) is a Python library for reading inputs and writing outputs of APEER modules. The ADK will take care of reading inputs from previous modules in APEER and writing your outputs in the correct format for the next module.

This is a bash file that you can execute from the command prompt. This file contains 2 lines of code. The first line builds a docker and the second line runs the docker. You can use the first command on any system (Windows/Mac/Linux) but the second command may not work on certain systems. This is because Windows uses different convention for folder and file paths. A separate command for Windows users is given later in this tutorial. So if you are a Windows user you may ignore this file altogether. Non-windows users, please study the second command in detail – it runs the docker created using the first command using the parameters defined in wfe.env file.
The docker file generated here is called ‘apeer/geometric_transformation’. You can leave this name as-is for all modules. This is because if the name gets changed for every module the local docker repositories will fill up the storage. Each docker container installs all dependencies, meaning 3 dockers containing Python code will install full Python and libraries 3 different times. It is ok if the geometric_transformation docker gets overwritten as it is used for your local testing only.


This is the primary docker file that contains a few lines of code. The first line points to the Docker repository that needs to be installed within the container. For a list of all available Docker repositories please visit The default module you just created uses Python 3. The Dockerfile also looks at all the library requirements from the requirements.txt file and installs them inside the container. It also copies the apeer_main, geometric_transformation python files and the json file for module specifications.

This is the primary python file that contains the code for your module. The default module you created contains Python code to transform the input image by applying rotation, shift in x and y, axes, respectively. The first function (execute) in this file takes care of reading and writing OME-TIFF file and applying the code within a function to every image in the OME-TIFF 5D array.
def execute(image_path, rotation_angle, shift_x, shift_y):
# Returned value is a 5D array of order (T, Z, C, X, Y)
(array5d, omexml) = io.read_ometiff(image_path)
# Apply 2D function to 5D array
result5d = processing.apply_2d_trafo(_geometric_transformation, array5d, angle=rotation_angle, shift_x=shift_x, shift_y=shift_y)
# In case you have a 3D function that acts on a whole Z-Stack use this code:
# The order of the 3D input image of trafo3D should be: (Z,X,Y)
#arrayOut5D = processing.apply_3d_trafo_zstack(_geometric_transformation, array5d, angle=rotation_angle)
# In case you have a 3D function that acts on a whole RGB image use this code:
# The order of the 3D input image of trafo3D should be: (C,X,Y)
#arrayOut5D = processing.apply_3D_trafo_rbg(_geometric_transformation, array5d, angle=rotation_angle)
image_name = os.path.basename(image_path)
io.write_ometiff(image_name, result5d, omexml)
return {'output_image': image_name}
In this code, the function that transforms images is called _geometric_transformation.
def _geometric_transformation(image2d, angle, shift_x, shift_y):
image_rotated = ndi.rotate(image2d, angle, reshape=False)
image_shifted = ndi.shift(image_rotated, (float(shift_x), float(shift_y)))
return image_shifted
The last few lines of code are used to execute this python file locally, using the parameters defined.
# Test code locally
if __name__ == "__main__":
execute("input/nucleiTubolin.ome.tiff", 45.0, 20, 50)


This file contains the code to define the interface for your module, including input and output parameters AND the user interface options for these inputs and outputs. You will edit this file later using an easy to use online tool at


This file contains all the libraries that need to be installed within the container (see Dockerfile). It is very important for you to specify the specific version for individual libraries. This is to ensure that your module works fine in future even when updated versions of libraries are released.


This file contains the input parameters for local Docker testing, in case the bash file is used (see to run Docker build and run commands. This file is relevant for MAC and Linux users but not for Windows users (as of Apr. 2019) since Windows users will ignore the bash file altogether to use custom commands (defined later).
Last modified 2yr ago
Copy link