CartesianIndex to Arrays of index

Dear all, I have some problems with CartesianIndex. In numpy when I want to index of nonzero elements I can do like this:

>>> x = np.array([[3, 0, 0], [0, 4, 0], [5, 6, 0]])
>>> x
array([[3, 0, 0],
       [0, 4, 0],
       [5, 6, 0]])
>>> a,b=np.nonzero(x)
>>> a
array([0, 1, 2, 2])
>>> b
array([0, 1, 0, 1]))

In Julia

>>> x = [3 0 0; 0 4 0; 5 6 0]
3×3 Array{Int64,2}:
 3  0  0
 0  4  0
 5  6  0
>>> findall(x.>0)
4-element Array{CartesianIndex{2},1}:
 CartesianIndex(1, 1)
 CartesianIndex(3, 1)
 CartesianIndex(2, 2)
 CartesianIndex(3, 2)

How can I get an variable a and b like in Python where a = [1,3,2,3] and b = [1,1,2,2]?

1 Like

Firstly, if you want all non-zero, you should write findall(!iszero, x), since x.>0 will give you just positive-valued elements.

Secondly, you can convert and extract a and b like this:

julia> inds = Tuple.(findall(!iszero, x))
4-element Array{Tuple{Int64,Int64},1}:
 (1, 1)
 (3, 1)
 (2, 2)
 (3, 2)

julia> a = first.(inds)
4-element Array{Int64,1}:
 1
 3
 2
 3

julia> b = last.(inds)
4-element Array{Int64,1}:
 1
 1
 2
 2

I think it is a bit risky to rely on access to internal fields, like .I, it’s better to convert to Tuple.

Thirdly, you should ask yourself if this is really necessary. Why do you need a and b separately? Cartesian indices are constructed in such a way that they should be easy and convenient to use without destructuring them like this. Perhaps you have a good reason, but sometimes Matlab and Python users ask for this because they are not used to the way CartesianIndex works.

1 Like

Thank you. It is working well. You are right, I am Python users so I am not sure how to do it in Julia way. I need a and b separately because I want to make plot from it e.g.

Using Plots

plot(a,b)

As far as I know, CartesianIndex can not be used as input in plot function so thats why I need a and b separately.

CartesianIndex supports getindex (i.e. i[j]), so you can do:

inds = findall(!iszero, x)
a = getindex.(inds, 1)
b = getindex.(inds, 2)
5 Likes

That would work really well with a hypothetical getindex dot syntax:

a = inds.[1] 
b = inds.[2] 
2 Likes

Although plot currently doesn’t support CartesianIndexs, it does support Tuples, so after

inds = Tuple.(findall(!iszero, x))

there’s no need to “unzip” the vector-of-tuples inds into a and b. It is possible to

plot(inds)

directly.

If one wants to stick to the convention of putting the first index on the y-axis, starting at the top, then one could write:

plot(reverse.(inds), yaxis=:flip)