# Boolean indexing with multidimensional array

I have been trying to filter a 2d-array with boolean indexing without much success. For instance,

``````B = randn(5,5)
s = B .> 0
B[s] # this produces a 1d array with those values that give s == true
``````

However, since I want is to plot with `contourf` those values in `B[s]` keeping those that does not satisfy the the `s` condition as well. The problem is that I get the 1d-array satisfying the `s` conditions instead of the whole 2d-array and the plot does not work with this. What I tried to do to obtain the desired result is

``````B.*s
``````

which gives the filtered matrix with the same original size of `B`. But not sure if this is an effective way of doing things, especially when lengths of arrays goes up to, say 10^4.

Itâ€™s a bit hard to understand what you want the end result to be for the cases where the element is `< 0`.

Perhaps you are looking for

``````julia> clamp.(B, 0, Inf)
5Ă—5 Array{Float64,2}:
0.0       1.63247    0.0       0.0       0.0
1.23743   0.0191958  0.417646  0.0       1.17548
0.0       0.0        0.42163   0.601486  0.726729
0.0       0.0        0.0       0.0       0.360118
0.420498  0.0        0.0       2.44904   0.0
``````
2 Likes

I was trying to plot with `contourf` a complex variable showing only those values that have zero imaginary part, discarding the others, but keeping the same size of the original array. The working example wasnâ€™t probably appropriate enough (noted). Here it goes again:

``````julia> B
3Ă—3 Array{Complex{Float64},2}:
0.542545+0.0im        0.925355-0.487208im    1.65225+0.806615im
-0.927869+0.847093im  -0.309946+1.53378im    0.444565+0.0im
-0.048035+0.260424im   0.937434+0.0im       -0.153685-1.71329im
``````

Now, if I do `s = imag.(B) .== 0`, then

``````B[s]
3-element Array{Complex{Float64},1}:
0.5425454 + 0.0im
0.937434 + 0.0im
0.44456454 + 0.0im
``````

But is hard to plot this way. What I really want is the original matrix `B` with those values that have zero imaginary part sent to zero. For instance,

``````julia> B.*s
3Ă—3 Array{Complex{Float64},2}:
0.542545+0.0im       0.0-0.0im       0.0+0.0im
-0.0+0.0im      -0.0+0.0im  0.444565+0.0im
-0.0+0.0im  0.937434+0.0im      -0.0-0.0im
``````

Hope is illustrative enough.

Indexing is, at its core, simply a selection API. It chooses which locations you want to have returned. Or modified, in the case of `setindex!`. As such, you can use boolean indexing to change the values as youâ€™d like:

``````B[imag.(B) .== 0] .= 0
``````

Broadcasted `clamp` is another great tool as @kristoffer.carlsson mentions, as is broadcasted `ifelse`:

``````ifelse.(imag.(B) .== 0, missing, B)
``````
1 Like

If youâ€™re worried about runtime, the best way to avoid it is to plot fewer points. The plotting library runtime will be orders of magnitude larger than the difference in runtime between indexing methods. Your screen only has so many pixelsâ€“you wonâ€™t lose much by downsampling your array to the desired plotting resolution.

``````using Plots, BenchmarkTools

function full_contour!(A)
A[imag(A) .< 0] .= 0
contourf(abs.(A))
end

function resampled_contour(A, res)
B = A[1:(size(A,1)Ă·res):end, 1:(size(A,2)Ă·res):end]
B[imag(B) .< 0] .= 0
contourf(abs.(B))
end

@btime full_contour!(A)           setup=(A = randn(ComplexF64, 5000, 5000));
@btime resampled_contour(\$A, 500) setup=(A = randn(ComplexF64, 5000, 5000));
``````
``````1.180 s (2848 allocations: 670.74 MiB)    # full_contour!
12.141 ms (2850 allocations: 10.72 MiB)   # resampled_contour
``````

Yeah, both worked. Thank you guys.

Donâ€™t forget comprehension! (Which creates a new matrix.) Also note that you can use `isreal` to check for zero imaginary part.

``````C = [isreal(x) ? 0.0im : x for x in B]
``````
1 Like

I took for granted that if the variable is actually complex, `isreal` would be false independently of the values. Good to know. Thanks.