# How to think about indices and cartesian coordinates?

**URL:** <https://discourse.julialang.org/t/how-to-think-about-indices-and-cartesian-coordinates/95972>\
**Category:** New to Julia\
**Tags:** question, plotting, plots, matrix\
**Created:** [March 12, 2023, 7:12pm UTC](https://discourse.julialang.org/t/how-to-think-about-indices-and-cartesian-coordinates/95972 "2023-03-12T19:12:20Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![isaque](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/isaque/32/47634_2.png) [@isaque](https://discourse.julialang.org/u/isaque)\
**Post date:** [March 12, 2023, 7:12pm UTC](https://discourse.julialang.org/t/how-to-think-about-indices-and-cartesian-coordinates/95972/1 "2023-03-12T19:12:20Z")

</div>

Hello everyone!

I am new to Julia and I am writing a simple simulation that uses a cartesian grid and numerical derivatives. I would like to confirm if my thinking is correct.

I start by defining simple grids for X, Y and a scalar field f which in this case is just Y.

```julia
n = 3
X = ones(Float64, n) * collect(1:n)'
Y = collect(1:n) * ones(Float64, n)'
f = Y

```

f is what I would expect:

```julia
3×3 Matrix{Float64}:
 1.0 1.0 1.0
 2.0 2.0 2.0
 3.0 3.0 3.0

```

That is, `f[3,1] #=> 3`

I also define a simple gradient function:

```julia
function ∇(q::Matrix{Float64})
    ∇q_x = zeros(n,n)
    ∇q_y = zeros(n,n)

    for j in 2:n-1, i in 2:n-1
        ∇q_x[i,j] = (q[i,j+1] - q[i,j-1])/2
        ∇q_y[i,j] = (q[i+1,j] - q[i-1,j])/2
    end

    Dict(:x => ∇q_x, :y => ∇q_y)
end

```

Is it correct to think of the first index (`i`) as the y direction, and the second index (`j`) as the x direction? That feels odd to me.  
I understand it may just be a matter of convention, but when I try to visualize it, it does appear that Julia prefers it that way.

```julia
using Plots; gr()
heatmap(f, c=:blues)
quiver!(X, Y, quiver=(∇(f)[:x], ∇(f)[:y]), c=:white, linewidth=5)

```

 ![Screen Shot 2023-03-12 at 3.43.40 PM](https://global.discourse-cdn.com/julialang/original/3X/c/f/cfbfc9a7b730df2a7b1bf4a5b77e79e39a2470b1.png)

Any thoughts are greatly appreciated!

---

<div class="post-metadata">

**Author:** ![aramirezreyes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aramirezreyes/32/42573_2.png) [@aramirezreyes](https://discourse.julialang.org/u/aramirezreyes)\
**Post date:** [March 12, 2023, 10:10pm UTC](https://discourse.julialang.org/t/how-to-think-about-indices-and-cartesian-coordinates/95972/2 "2023-03-12T22:10:42Z")

</div>

I think this is more about how the plotting library does the heatmap (not julia itself). For example, in CairoMakie,

```julia
fig,ax = heatmap(ff, colormap=:blues)
arrows!(ax,X[1,:], Y[:,1], ∇(f)[:x], ∇(f)[:y], color=:white, linewidth=5)
fig

```

Produces this:

 ![imagen](https://global.discourse-cdn.com/julialang/original/3X/f/6/f6d5e52009ab957c5fdd944cb8fdd6f9abca3c57.png)

There is not a “correct” way for showing this, so that is why some libraries (even outside julia) have different approaches.

For Makie it has been discussed for example here:

[heatmap permutes data · Issue #1791 · MakieOrg/Makie.jl · GitHub](https://github.com/MakieOrg/Makie.jl/issues/1791)  
[Correct axes bug for heatmaps & images by IanButterworth · Pull Request #98 · JuliaPlots/AbstractPlotting.jl · GitHub](https://github.com/JuliaPlots/AbstractPlotting.jl/pull/98)  
[X / Y axes swapped in heat map · Issue #295 · MakieOrg/Makie.jl · GitHub](https://github.com/MakieOrg/Makie.jl/issues/295)  
[Resolved: Heatmap transposes matrices · Issue #205 · MakieOrg/Makie.jl · GitHub](https://github.com/MakieOrg/Makie.jl/issues/205)

As for your simulations, as long as you are consistent, there should not be a problem, I think!

(Edit: to show the CairoMakie also with arrows)

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [March 12, 2023, 11:07pm UTC](https://discourse.julialang.org/t/how-to-think-about-indices-and-cartesian-coordinates/95972/3 "2023-03-12T23:07:07Z")

</div>

> [@isaque](#):
>
> Is it correct to think of the first index (`i`) as the y direction, and the second index (`j`) as the x direction?

It is really neither correct nor incorrect, it is really up to you to choose a convention for yourself. Unfortunately.

The problem is that we are used to thinking of x as the first dimension and y as the second dimension, while in linear algebra the first dimension is ‘downwards’ and the second dimension is ‘across’.

Every time, I struggle with choosing a convention, and I personally believe everything would be much nicer if the first index always was the x-direction, and also indicated column (the opposite of today).

So, it’s up to you.

> [@isaque](#):
>
> ```julia
> X = ones(Float64, n) * collect(1:n)'
> Y = collect(1:n) * ones(Float64, n)'
> 
> ```

I urge you to not get into the habit of using `collect`. It is wasteful and pointless here. Forget you ever heard of that function. Remove it from all your codes, and don’t use until your code stops working without it.

---

<div class="post-metadata">

**Author:** ![PeterSimon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petersimon/32/25193_2.png) [@PeterSimon](https://discourse.julialang.org/u/PeterSimon)\
**Post date:** [March 13, 2023, 2:17am UTC](https://discourse.julialang.org/t/how-to-think-about-indices-and-cartesian-coordinates/95972/4 "2023-03-13T02:17:26Z")

</div>

> [@DNF](#):
>
> I urge you to not get into the habit of using `collect`. It is wasteful and pointless here.

To elaborate a little on @DNF’s good advice, in case it’s not clear:

```julia
julia> n = 3
3

julia> xs = 1:n
1:3

julia> ys = 1:n
1:3

julia> f = [y for y in ys, x in xs] # or any other function of (x,y)
3×3 Matrix{Int64}:
 1 1 1
 2 2 2
 3 3 3

```

You never need to explicitly form your `X` or `Y` matrices. You can either broadcast, or use a multidimensional array comprehension as above. Here’s an example of broadcasting:

```julia
julia> fun(x,y) = y
fun (generic function with 1 method)

julia> fun.(xs', ys)
3×3 Matrix{Int64}:
 1 1 1
 2 2 2
 3 3 3

```

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [March 13, 2023, 2:49am UTC](https://discourse.julialang.org/t/how-to-think-about-indices-and-cartesian-coordinates/95972/5 "2023-03-13T02:49:21Z")

</div>

> [@DNF](#):
>
> I urge you to not get into the habit of using `collect`. It is wasteful and pointless here. Forget you ever heard of that function. Remove it from all your codes, and don’t use until your code stops working without it.

Glad I’m not the only person who dislikes this function. I always had an uneasy feeling about it. IMO, most of what `collect` is used for should be functionality of the `Array` constructor.

> [@PeterSimon](#):
>
> To elaborate a little on @DNF’s good advice, in case it’s not clear

To elaborate a little further: not only is using comprehensions more legible, but it’s also faster:

```julia
julia> using BenchmarkTools
       a = @btime ones(Float64, 3) * collect(1:3)'
       b = @btime Float64[j for i=1:3, j=1:3]
       c = @btime ((x,y)->Float64(x)).((1:3)',1:3)
       a == b == c
  60.652 ns (3 allocations: 288 bytes)
  16.917 ns (1 allocation: 128 bytes)
  16.817 ns (1 allocation: 128 bytes)
true

```

---

<div class="post-metadata">

**Author:** ![isaque](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/isaque/32/47634_2.png) [@isaque](https://discourse.julialang.org/u/isaque)\
**Post date:** [March 15, 2023, 9:27pm UTC](https://discourse.julialang.org/t/how-to-think-about-indices-and-cartesian-coordinates/95972/6 "2023-03-15T21:27:33Z")

</div>

> [@aramirezreyes](#):
>
> There is not a “correct” way for showing this, so that is why some libraries (even outside julia) have different approaches.

Great to know! That’s what I assumed but I wondered about the convention in the Julia community. Thank you for introducing me to CairoMakie.

> [@DNF](#):
>
> It is really neither correct nor incorrect, it is really up to you to choose a convention for yourself. Unfortunately.
> 
> The problem is that we are used to thinking of x as the first dimension and y as the second dimension, while in linear algebra the first dimension is ‘downwards’ and the second dimension is ‘across’.
> 
> Every time, I struggle with choosing a convention, and I personally believe everything would be much nicer if the first index always was the x-direction, and also indicated column (the opposite of today).

I agree with you. For now I am inclined to adopt the convention where the first index is the y-coordinate since it is “downwards”, even if it feels a bit odd. In any case, it is great to know that I’m not alone in struggling to choose a convention.

> [@DNF](#):
>
> I urge you to not get into the habit of using `collect`. It is wasteful and pointless here. Forget you ever heard of that function. Remove it from all your codes, and don’t use until your code stops working without it.

Thank you for the great advice @DNF! And thank you @PeterSimon and @uniment for elaborating and providing examples. That was very helpful for better understand the problem with `collect`. I was able to shave a significant amount of time from my simulation by eliminating all the calls to `collect`!
