TIFF image cannot be loaded, returned MethodError: no method matching size

Good day everyone,

Thank you in advance for reading this. I am a Python user but I have to run a pipeline that was built using Julia. It’s here: github [dot] com [slash] kharchenkolab [slash] Baysor .

I ran into an error with this particular Julia script: (src/data_loading/prior_segmentation.jl). Specifically, this code (Line 109) seems to be the one causing an error. My question is: Why cannot the pipeline load my TIFF image, despite mine has the same image type and value type as the author’s example image?

function filter_segmentation_labels!(segmentation_labels::MT where MT <: AbstractArray{<:Integer}, segment_per_transcript::Vector{<:Integer}; min_molecules_per_segment::Int)
           n_mols_per_label = count_array(segment_per_transcript, max_value=maximum(segmentation_labels), drop_zero=true)

Here’s the error message:

This code essentially reads and loads a TIFF image. I examined author’s example image which has size 3734x17219, Array{Gray{N0f16}, 2} with eltype Gray{N0f16}. Other than the size of my TIFF image (which is 1608x1608), everything else is the same.

Another observation is that, when loaded into ImageJ: author’s image’s values ranges between 0 and 355. While mine is just 0 and 1, I have also tried 0 and 255. But the pipeline still failed. Though, when I loaded these images using Julia, the maximum and minimum returned are as follow: (Why are the values so different??)

julia> maximum(example_image)
Gray{N0f16}(0.01486)

julia> minimum(example_image)
Gray{N0f16}(0.0)

julia> maximum(my_image)
Gray{N0f16}(2.0e-5)

julia> minimum(my_image)
Gray{N0f16}(0.0)

First screenshot below displays information about author’s example image. example_image_info.png - Google Drive

Second screenshot below displays information about my image. my_image_info.png - Google Drive

There’s a note about (0 - 1) normalization in the documentation:

https://juliaimages.org/latest/tutorials/quickstart/#The-0-to-1-intensity-scale

in case it helps.

I tried to install this into an empty project on v1.10.4 on MacOS, but it failed with many errors. (Installation is not straightforward anyway, since it compiles stuff.) I also noticed that there were a number of packages that were marked as out of date:

⌃ [13f3f980] + CairoMakie v0.10.12
⌃ [35d6a980] + ColorSchemes v3.20.0
⌅ [c3611d14] + ColorVectorSpace v0.9.10
⌅ [927a84f5] + DelaunayTriangulation v0.8.12
⌃ [429591f6] + ExactPredicates v2.2.6
⌃ [6a86dc24] + FiniteDiff v2.17.0
⌅ [3955a311] + GridLayoutBase v0.9.2
⌃ [f67ccb44] + HDF5 v0.16.16
⌃ [c817782e] + ImageBase v0.1.5
⌅ [a09fc81d] + ImageCore v0.9.4
⌃ [787d08f9] + ImageMorphology v0.3.2
⌅ [d1acc4aa] + IntervalArithmetic v0.21.2
⌅ [0b1a1467] + KrylovKit v0.6.1
⌅ [ee78f7c6] + Makie v0.19.12
⌅ [20f20a25] + MakieCore v0.6.9
⌅ [0a4f8689] + MathTeXEngine v0.5.7
⌃ [92933f4c] + ProgressMeter v1.7.2
⌃ [90137ffa] + StaticArrays v1.5.26
⌃ [2913bbd2] + StatsBase v0.33.21
⌅ [06e1c1a7] + TiledIteration v0.3.1
⌃ [239c3e63] + Vega v2.4.1
⌃ [112f6efa] + VegaLite v3.0.1
⌅ [68821587] + Arpack_jll v3.5.1+1
⌅ [e9f186c6] + Libffi_jll v3.2.2+1
⌅ [fe0851c0] + OpenMPI_jll v4.1.6+0

Not that this would stop the package working, of course, but something to consider when troubleshooting.

Perhaps general Julia troubleshooting help isn’t what’s needed here - specialized assistance from the project’s maintainers might be required. Good luck!

1 Like

Long shot

Is your TIFF file a GeoTiff? There is a kind of informal convention that tifs with 2 Fs are Geotiffs and with a single F are plain tifs. Now, not all tif readers can read GeoTiffs, specially when they are written by blocks.

1 Like

Hi and welcome to the Julia community!

Is the 355 a typo for 255? And how did you determine this range (presumably not within Julia?)? Related, are you supposed to have 8 bits or 16 bits of precision?

As cormullion already mentioned, Gray{N0f16} is a normalised 16-bit integer format. I.e. from the outside it looks like it is floating point in [0, 1] , but internally it is represented using UInt16. Your maximum (as a normalised quantity) is very small, since the integer range you mention (be it [0, 255] or [0, 355]) is much smaller than what you can represent using UInt16 ([0, 65535]).

The top error is saying you want to use a function size(::MappedArrays...) which is not defined. Below it is mentioned that this function actually sort of exists, but there’s a world age problem.

The world age problem occurs when you dynamically (re)define functions. As a simple example, consider

julia> function g(x)
           return f(x)^2
       end;

julia> function h(x)
           @eval f(x) = 2x
           return g(x)
       end;

julia> h(1)
ERROR: MethodError: no method matching f(::Int64)
The applicable method may be too new: running in world age 31505, while current world is 31506.

Closest candidates are:
  f(::Any) (method too new to be called from this world context.)
   @ Main REPL[2]:2

Stacktrace:
 [1] g(x::Int64)
   @ Main .\REPL[1]:2
 [2] h(x::Int64)
   @ Main .\REPL[2]:3
 [3] top-level scope
   @ REPL[3]:1

In principle, at the time we ask for g(1), f will be defined. But it did not yet when we called h(1). You can read a bit more about the world age problem in the Julia documentation on redefining methods, or in the documentation of FileIO.jl.

I haven’t looked too much into the source code of Baysor, but I noticed it makes use of FileIO.jl and LazySubmodules. That sounds like they might be defining methods at runtime, including presumably the necessary version of size. So I guess it could make sense that the world age problem might pop up.

Now, I’m assuming the package works fine for the authors. To be able to help you further, it would then be useful if you could provide a minimal working example of concretely how you are using Baysor.

1 Like

Hi everyone and eldee,

Thank you very much for your prompt reply. All of you are much more helpful than even my supervisor and lab members who gave no response. :cry: I will carefully go through each of your suggestions!

@eldee: According to the author’s example segmentation image here, I discovered using Python that it’s Uint16. This is the link to author’s TIFF image. segmentation.tiff - Google Drive

@eldee: Excuse me for the inaccuracy reporting between 0 and 355. Below are the values of author’s example image when I loaded into Python or ImageJ. (Certainly, the minimum values started from 0 and all the way to as big as what you see here.)

image

Essentially, I had no issue running Baysor until I have to load up an image.

How to run Baysor…

Example 1: (Baysor runs properly)
Given a barcoding decoding method’s barcodes.csv (which contains “x” and *“*y” location of a gene “target”, below is the command line to run Baysor without prior segmentation

julia --cpu-target="native" /home/jtsui/.julia/bin/baysor run -x x -y y -g target
    -c baysor_config.toml 
    -o baysor_output.csv 
    barcodes.csv

Example 2: (Baysor runs properly)
Given a barcoding decoding method’s CSV (which contains “x” and “y” location of a gene “target”, below is the command line to run Baysor using cell_index as a prior, which is a column added to the pre-existing barcodes.csv.

julia --cpu-target="native" /home/jtsui/.julia/bin/baysor run -x x -y y -g target
    -c baysor_config.toml 
    -o baysor_output.csv 
    barcodes.csv :cell_index

Example 3: (Baysor CRASHED !!)
Given a barcoding decoding method’s CSV (which contains “x” and “y” location of a gene “target”, below is the command line to run Baysor using prior segmentation. Author defined that this prior segmentation is a nuclei segmented image, which can be either binary or labeled. In author’s example image, it is labeled. In my case, it’s just a binary image.

julia --cpu-target="native" /home/jtsui/.julia/bin/baysor run -x x -y y -g target
    -c baysor_config.toml 
    -o baysor_output.csv 
    barcodes.csv $nuclei_segmentation_file

I don’t think the baysor_config.toml matters. But here’s what it contains:

Running the STARmap data example in the GitHub repo ((...)\.julia\bin>baysor run -x x -y y -o (...)/baysor_output.csv -m 10 -s 1 (...)\molecules.csv (...)\segmentation.tiff), I get output like

[11:20:03] Info: Run Ra3522874e
[11:20:03] Info: (2024-08-11) Run Baysor v0.6.2
[11:20:03] Info: Loading data...
[11:20:05] Info: Loaded 949505 transcripts
[11:20:08] Info: Loading segmentation mask..
[11:20:10] Warning: Minimum transcript coordinates are < 1: (8, 0). Filling it with 0.
└ Baysor.DataLoading (...)\src\data_loading\prior_segmentation.jl:30
[11:20:11] Info: Done

I assume your crash with your .tiff file occurs after the Loading segmentation mask print? Could you also provide this .tiff file, or preferably a toy version (for size, complexity, and possibly ethical and legal reasons) which gives the same error?

1 Like

Hello @eldee,

Thank you for testing it out !! Indeed you are correct. The errors occurred after the “loading segmentation mask print”.

What strikes me is that when I used the float version of my image, Baysor actually worked with some Field of Views, while some indeed crashed.

However, with the int-version of my image, Baysor crashed on all Field of Views.

This is the original float version of my image: drive.google.com/file/d/1VcdvQrUlTiuT1mVC0zNZRB7zQxx7x5Vf/view?usp=sharing

This is the integer version of my image:
drive.google.com/file/d/1RBAjyBVEP2414muXzjR8vca8Apr6B2Zh/view?usp=sharing

This is the Python script I generated to convert float → int:

from skimage import io
import numpy as np
import os

# Define the input and output paths
input_path_template = "aligned_nucleus_{:03}.tif"
output_path_template = "int_aligned_nucleus_{:03}.tiff"

# Loop through each Field of View (FOV)
for fov in range(15):
    # Construct the file path
    input_path = input_path_template.format(fov)
    output_path = output_path_template.format(fov)

    # Open the image
    img = io.imread(input_path)

    # Convert the image to a NumPy array
    img_array = np.array(img)

    # Convert float values to binary integers (0 or 1) and then to int32
    int_array = (img_array > 0).astype(np.uint16)

    # Save the converted image as a TIFF file
    io.imsave(output_path, int_array)

    print(f"Converted and saved {output_path}")

print("All images converted successfully!")

Hmm, I don’t run into any issues when using your integer .tiff file (nor with the floating point version for that matter).

(...)\.julia\bin>baysor run -x x -y y -o (...)/baysor_output.csv (...)\molecules.csv (...)\int_aligned_nucleus_000.tiff
[13:19:09] Info: Run R0d809a0ab
[13:19:09] Info: (2024-08-11) Run Baysor v0.6.2
[13:19:09] Info: Loading data...
[13:19:11] Info: Loaded 949505 transcripts
[13:19:14] Info: Loading segmentation mask...
[13:19:16] Warning: Maximum transcript coordinates are (3729, 17204), which is larger than the DAPI size: (1608, 1608). Filling it with 0.
└ Baysor.DataLoading (...)\src\data_loading\prior_segmentation.jl:26
[13:19:16] Warning: Minimum transcript coordinates are < 1: (8, 0). Filling it with 0.
└ Baysor.DataLoading (...)\src\data_loading\prior_segmentation.jl:30
[13:19:16] Info: Done
[13:19:16] Info: Estimating noise level
(...)

Of course, I’m mixing STARmap data and your data here, which presumably explains the Warnings. But if the problem is really with loading the segmentation, this should not matter I think.

To potentially simplify everything a bit, do you also get an error when just using FileIO.load on your image path?

(In case you’re new to Julia and unsure how to do this: open up a Julia terminal and paste

using Pkg
Pkg.add("FileIO")
using FileIO

load("int_aligned_nucleus_000.tiff")  # or whatever is the correct path to your problematic tiff

)

PS:

  • In general it would be easier if you would include logs etc. as text, e.g. just post (the contents of) config.toml instead of a screenshot, and the same for error messages.

  • As mentioned above, I doubt it would make a difference, but you could perhaps also post your baysor_config.toml and barcodes.csv. Then I can check if I still don’t get any issues when I run the same command with the same data (though note that I’m using the baysor (or in my Windows situation technically baysor.cmd) file in .julia/bin directly, without the prepended julia --cpu-target="native" (which doesn’t work for me).

1 Like

Hello @eldee,

Thank you for continuously testing for me! I have tried loading TIFF using FileIO, and I had no issues with it.

Here are the files: https://drive.google.com/drive/folders/1-cLGHAcxZSs3yS7-viHF8r87UhFC8TnU?usp=sharing

Hi @eldee,

I have just re-run Baysor using float images. As expected, some Field of Views failed while some succeeded. I have enclosed the logs in the link above too!

Here’s a summary:
float TIFF:

  • FOV 0: succeeded
  • FOV 1: failed

integer TIFF:

  • FOV 0: failed
  • FOV 1: failed

My bad, the error is actually in sparse. So could you check if

using SparseArrays, FileIO, LazyModules  # first install if necessary
@lazy import ImageCore = "a09fc81d-aa75-5fe9-8630-4744c3626534"
path = "int_aligned_nucleus_000.tiff"  # (adjust if needed)
load(path) |> ImageCore.channelview |> ImageCore.rawview |> sparse |> dropzeros!

works?

Also with the proper barcodes_000.csv and config.toml, I’m not encountering any problems.

(...)\.julia\bin\baysor run -x x -y y -g target -c config.toml -o baysor_output.csv barcodes_000.csv int_aligned_nucleus_000.tiff
[14:44:19] Info: Run Rbb3d3c01a
[14:44:19] Info: (2024-08-11) Run Baysor v0.6.2
[14:44:19] Info: Loading data...
[14:44:20] Info: Excluding genes: Blank-01
[14:44:21] Info: Loaded 88917 transcripts
[14:44:24] Info: Loading segmentation mask...
[14:44:25] Warning: Minimum transcript coordinates are < 1: (3, 0). Filling it with 0.
└ Baysor.DataLoading (...)\src\data_loading\prior_segmentation.jl:30
[14:44:25] Info: Done
[14:44:25] Info: Estimating noise level

You could try reinstalling Baysor (and whatever might be relevant (e.g. Julia itself)). It’s also possible that your issue only manifests on Linux, in which case I can’t help you.

As cormullion also already mentioned, it might be a good idea to open up an issue on GitHub to directly ask the package authors.

Hi @eldee,

Thank you so much for all your help!!! Yes I have created an issue on GitHub, hopefully they’ll reply soon! And your code indeed works!

Since it works for you, I was wondering what version of Julia are you using? And how did you install Julia? Did you use docker or juliaup?

You’re welcome. Here’s my versioninfo():

julia> versioninfo()
Julia Version 1.10.4
Commit 48d4fd4843 (2024-06-04 10:41 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: 8 × Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-15.0.7 (ORCJIT, skylake)
Threads: 8 default, 0 interactive, 4 GC (on 8 virtual cores)
Environment:
  JULIA_NUM_THREADS = auto

installed via juliaiup.

Note that the code I posted was basically just the line where you got the original error (prior_segmentation.jl:60) together with the necessary imports. So it’s weird that this runs fine, but the actual code does not. Looking at the stacktrace from your first post, LazySubmodules was used there, which we are skipping in the short code fragment.

I thought disabling _LAZYMODE in LazySubmodules.jl (by using const _LAZYMODE = Ref(false) and the normal Julia sysimage) could help, but interestingly enough, this now also gives me the world age problem

>julia -e "using Baysor; exit(Baysor.command_main())" run -x x -y y -g target -c config.toml -o baysor_output.csv barcodes_000.csv int_aligned_nucleus_000.tiff
WARNING: method definition for InitialParams at C:\Users\Laurens\.julia\packages\Baysor\vZCu7\src\processing\models\InitialParams.jl:6 declares type variable N but does not use it.
[16:39:09] Info: Run Re988a9898
[16:39:10] Info: (2024-08-11) Run Baysor v0.6.2
[16:39:10] Info: Loading data...
[16:39:14] Info: Excluding genes: Blank-01
[16:39:14] Info: Loaded 88917 transcripts
[16:39:16] Info: Loading segmentation mask...
ERROR: MethodError: no method matching size(::MappedArrays.MappedArray{UInt16, 2, Base.ReinterpretArray{FixedPointNumbers.N0f16, 2, ColorTypes.Gray{FixedPointNumbers.N0f16}, Matrix{ColorTypes.Gray{FixedPointNumbers.N0f16}}, true}, typeof(reinterpret), ImageCore.var"#39#40"{FixedPointNumbers.N0f16}})
The applicable method may be too new: running in world age 31792, while current world is 31800.

Closest candidates are:
  size(::MappedArrays.AbstractMappedArray) (method too new to be called from this world context.)
...
(no LazySubmodules involved)

The good news then is that this way I can sort of replicate your issue. The bad news is that I have no idea why :slight_smile:.

In fact, it turns out _LAZYLOAD is irrelevant for whether I get the problem or not, the relevant part seems to be me using the standard Julia sysimage. What is your .julia/bin/baysor actually? Is it an executable, some bash script, …?

Hi @eldee,

I feel excited that at least you are able to replicate my problem! :slight_smile:

So based on your finding, you meant that whether disabling _LAZYMODE or not would not have helped with resolving my issue. Was that correct?

My .julia/bin/baysor is a bash script.

Yes, indeed: the value of _LAZYMODE does not seem to affect the issue. (The test with the default sysimage and _LAZYMODE on was a late addition to the post, and I could have probably worded it more clearly.)

What happens if you run it as a bash script:

bash /home/jtsui/.julia/bin/baysor run -x x -y y -g target -c baysor_config.toml -o baysor_output.csv barcodes.csv int_aligned_nucleus_000.tiff

(i.e. replace julia by bash in your earlier terminal command)? If the baysor file has an extension (e.g. .sh), also try it with the extension.

1 Like

You have no clue how thankful I am to you. Thank you! I am literally crying since it’s been 2 weeks debugging and it stalled my progress as a PhD student and the project, while no one else in the lab seemed to know what to do. You’ve made my journey a little less lonely.

Everything is running even with the integer version of my images.

Though may I ask for the reasoning? What made you guess that I should run it natively instead of calling “Julia” and then call “Baysor”?

Thank you again!!

2 Likes

Glad I could help! Turns out the fix was quite easy :slight_smile: .

For the thought process, let me first post the Windows baysor.cmd for reference:

@echo off
:: generated by Comonicon for the CLI Application baysor
setlocal
set JULIA_PROJECT=(...)\.julia\scratchspaces\cc9f9468-1fbe-11e9-0acf-e9460511877c\env
(...)\julia.exe ^
    --sysimage=(...)\libbaysor.dll ^
    --startup-file=no ^
    --color=yes ^
    --compile=yes ^
    --optimize=2 ^
    -e "using Baysor; exit(Baysor.command_main())" %*
if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL%
endlocal

What’s happening here is that we are executing julia.exe with the correct project and sysimage (which contains precompiled methods), and making it run using Baysor; exit(Baysor.command_main()) with the supplied command-line arguments (run etc.). This is quite straightforward, and clearly a batch script: julia baysor.cmd will crash.

>julia baysor.cmd
ERROR: LoadError: UndefVarError: `@echo` not defined
in expression starting at (...)\baysor.cmd:1

From my previous test I realised that the sysimage is important, though I’m still not completely sure why the compiled sysimage solves the world age problem (if it is not due to LazySubmodules). As the (Windows) baysor file is in charge of setting the correct sysimage, it made sense to take a closer look at your baysor script. Since on your OS (Linux I presume) julia baysor ... did in fact run, I originally thought your baysor file must be something entirely different, and it sort of is, but also not really :slight_smile: .

In the bash script (run as a bash script) you’re again executing Julia with the proper project and sysimage. Any lines after the exec’s lines will not be reached. Importantly, here we’re not directly making Julia execute using Baysor; exit(Baysor.command_main()), but instead letting it run our ‘bash’ script (located at BASH_SOURCE[0]). When reading the file as a Julia script, the first lines will be ignored, as # and #= ... =# are used for comments. So the only actual code is

using Baysor
exit(Baysor.command_main())

The fact that the bash script contains valid Julia code explains why your julia baysor ... did run. But this skips setting up the correct sysimage, leading to the issue.

1 Like