Skip to content

Export

PciSeq

For probabilistic cell typing with pciSeq, a DAPI background image and gene spot positions must be exported.

Filtered DAPI

To export the anchor's filtered DAPI stitched image

from coppafisher import Notebook
from coppafisher.results import export_pciseq_dapi_image

nb = Notebook("/path/to/notebook")
export_pciseq_dapi_image(nb)

The DAPI image can then be loaded into memory by

import numpy as np

dapi_image = np.load("/path/to/dapi_image.npz")["arr_0"]
Unfiltered DAPI

To export the anchor's unfiltered DAPI stitched image

from coppafisher import Notebook
from coppafisher.results import export_pciseq_unfiltered_dapi_image

nb = Notebook("/path/to/notebook")
config_path = "/path/to/config.ini"
export_pciseq_unfiltered_dapi_image(nb, config_path)

The DAPI image can then be loaded into memory by

import numpy as np

dapi_image = np.load("/path/to/dapi_image.npz")["arr_0"]

Export gene reads into a compatible csv file by

from coppafisher import Notebook
from coppafisher.results import export_to_pciseq

nb = Notebook("/path/to/notebook")
export_to_pciseq(nb, method)

where method can be "omp", "prob", or "anchor" for each gene calling method. To set a score and/or intensity minimum threshold:

from coppafisher import Notebook
from coppafisher.results import export_to_pciseq

nb = Notebook("/path/to/notebook")
export_to_pciseq(nb, method, score_thresh, intensity_thresh)

score_thresh and intensity_thresh must be numbers. Use the Viewer to help decide on thresholds. intensity_thresh is set to 0.15 for OMP in the Viewer by default.

Custom Images

Additional custom images can be aligned with coppafisher images and gene spots provided that you have a dapi channel (or something similar to align with the anchor-DAPI image).

Extract the additional image(s)

The additional images must be extracted from ND2 files. You will likely require the DAPI channel for best results. They are saved as tiff files. If you do not have ND2 input files, you need to first manually convert them to tiff files.

from coppafisher.custom_alignment import extract_raw
from coppafisher import Notebook

config_file = "/path/to/used/config.ini"
custom_nd2 = "/path/to/input/file.nd2"
output_dir = "/path/to/extract/directory/"

nb = Notebook("/path/to/notebook")
extract_raw(
    nb,
    config_file,
    save_dir=output_dir,
    read_dir=custom_nd2,
    use_tiles=nb.basic_info.use_tiles,
    use_channels=[nb.basic_info.dapi_channel, 9, 23],
    reverse_custom_z=False,
)

use_channels can be any valid channel(s) inside the custom image .nd2 file. This will also extract the anchor round in the DAPI channel. You can reverse the z planes in the custom image by setting reverse_custom_z to True.

Config File

The config file must be a valid configuration, like the one used during the experiment. Therefore, the input_dir must point to a real input directory.

Stitch

The extracted raw anchor-DAPI images are stitched using coppafisher's stitch method. The custom image is stitched by the same method separately. This then needs to be registered with the anchor-DAPI in the next step. Do this for each custom image channel separately. I suggest starting with the dapi channels first

from coppafisher.custom_alignment import fuse_custom_and_dapi

fused_custom_dapi_image, fused_anchor_dapi_image = fuse_custom_and_dapi(nb, output_dir, channel=nb.basic_info.dapi_channel)

Dapi Register

Alignment is done using the package LineStuffUp maintained by Max Shinn (m.shinn@ucl.ac.uk). This allows control over the type of transformation to apply based on their custom images. Install via pip

python -m pip install LineStuffUp

Then start the interactive alignment process

import linestuffup.gui
from linestuffup.base import TranslateRotate

round_transform = linestuffup.gui.alignment_gui(
    fused_custom_dapi_image, fused_anchor_dapi_image, transform_type=TranslateRotate
)

Press Add new point and click twice to place two corresponding points. Do this a few times, preferably in various z planes too. Press Perform transform to see the resulting transform. Once you are happy with the result, close the napari window.

Type of Transform

You can change the type of transform you wish to find, please see the transfrom readme for details.

For example, you could use the more robust transform type of TranslateRotateRescale. It requires four points in every corner of the image on both edges of the z stack for best results.

Save and Load Transforms

Every transform can be saved and reloaded at a later point. You just need to save the text representation of the transform which can be found by

str(round_transform)

You can save it using Python

with open("/path/to/saved/transform.txt", "w") as file:
    file.write(str(round_transform))

It can be reloaded by

from linestuffup.base import *

with open("/path/to/saved/transform.txt", "r") as file:
    exec("round_transform = " + "\n".join(file.readlines()))

You can rename the variable from round_transform to anything.

Do not run exec on stranger's code (it could be malicious)!

You can now apply the resulting transform to the custom dapi image and save the result as a .tif file

import numpy as np
import tifffile

fused_custom_dapi_image_transformed = round_transform.transform_image(
    fused_custom_dapi_image, relative=fused_anchor_dapi_image.shape, force_size=True, labels=True
)
tifffile.imwrite("/path/to/saved/custom_dapi_image_transformed.tif", fused_custom_dapi_image_transformed)
del fused_custom_dapi_image_transformed
del fused_anchor_dapi_image

Non-Dapi Register

For a non-dapi custom image channel c, it is recommended to find a specific transform to move to the dapi channel for best registration. To do this, first find a transform to move into the dapi custom image's frame

from coppafisher.custom_alignment import fuse_custom_and_dapi
import linestuffup.gui
from linestuffup.base import TranslateRotate

fused_custom_channel_image, _ = fuse_custom_and_dapi(nb, output_dir, channel=c)

channel_transform = linestuffup.gui.alignment_gui(
    fused_custom_channel_image, fused_custom_dapi_image, transform_type=TranslateRotate
)

Now save the fully registered channel image

import tifffile

fused_custom_channel_image_transformed = (channel_transform + round_transform).transform_image(
    fused_custom_channel_image, relative=fused_custom_channel_image.shape, force_size=True, labels=True
)
tifffile.imwrite(f"/path/to/saved/custom_channel_{c}_image_transformed.tif", fused_custom_channel_image_transformed)
del fused_custom_channel_image_transformed
del fused_custom_channel_image