# Nonorthogonal axes in Makie (or maybe in other plotting package)

**URL:** https://discourse.julialang.org/t/nonorthogonal-axes-in-makie-or-maybe-in-other-plotting-package/86749
**Category:** Visualization
**Tags:** plotting, makie
**Created:** [September 4, 2022, 7:02am UTC](https://discourse.julialang.org/t/nonorthogonal-axes-in-makie-or-maybe-in-other-plotting-package/86749 "2022-09-04T07:02:19Z")
**Posts on this page:** 15
**Page:** 1

<div class="post-metadata">

### Author: ![fedoroff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fedoroff/32/53209_2.png) [@fedoroff](https://discourse.julialang.org/u/fedoroff)
#### Post date: [September 4, 2022, 7:02am UTC](https://discourse.julialang.org/t/nonorthogonal-axes-in-makie-or-maybe-in-other-plotting-package/86749/1 "2022-09-04T07:02:19Z")

</div>

Is it possible to make a plot (both in 2d and 3d) using non-orthogonal axes? Something similar to this ([link](https://mathematica.stackexchange.com/questions/222118/how-to-plot-with-non-orthogonal-axes))

 ![](https://global.discourse-cdn.com/julialang/original/3X/4/5/458a14265a27fc979a530a85a58d4ac703eda4fd.png)  
or this ([link](https://stackoverflow.com/questions/31271907/imshow-with-non-orthogonal-axes-i-e-parallelogram))  
 ![](https://global.discourse-cdn.com/julialang/original/3X/a/3/a38d7668f5a8de856357f3933c08c27b16c10f84.png)  
(though here simple image transformation is not enough for me; I want the axes transformed as well).

These types of plots appear in analysis of crystals where the atoms are arranged in a non-orthogonal lattice.

---

<div class="post-metadata">

### Author: ![empet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/empet/32/221303_2.png) [@empet](https://discourse.julialang.org/u/empet)
#### Post date: [September 4, 2022, 8:38am UTC](https://discourse.julialang.org/t/nonorthogonal-axes-in-makie-or-maybe-in-other-plotting-package/86749/2 "2022-09-04T08:38:50Z")

</div>

With Plots and ImageTransformations.jl you can transform the original image through a shear transformation or rotation:

```julia
using Plots, CoordinateTransformations, ImageTransformations, Images

n=2^8
I =[i for i in 0:n-1, j in 0:n-1]
h=heatmap(xor.(I, I' ), c=:plasma, xlim=(-25, 255+25), ylim=(-25, 255+25), 
                      colorbar=false, size=(350, 350))

savefig(h, "original.png")
img=load("original.png")
α = pi/9
M = [1 tan(α); 0 1]
tr = LinearMap(M) #shear transformation; 
imgw= warp(img, tr; fillvalue=1)

```

Rotation:

```julia
using Rotations
rot = recenter(RotMatrix(pi/4), ImageTransformations.center(img));
imgr = warp(img, rot, fillvalue=1)

```

![sheared-image](https://global.discourse-cdn.com/julialang/original/3X/f/8/f8ea5670961c289701405ecffdde5fad59d2f68c.png)  
 ![rotated](https://global.discourse-cdn.com/julialang/original/3X/3/4/34b77eb7ac9374201d971dd4cf87e25cc7abda81.png)

If none of the two types of transformations meet your requirements, then you can define a more general linear transformation, that maps the basis vectors to the direction you want:  
if

```julia
T([1,0]) = v₁
T([0,1]) = v₂

```

then define: `inv(M)=hcat(v₁, v₂)`.  
Note that the transformation passed to warp is the inverse transformation to be applied to the original image, because warp implements the backward geometric transformation from image processing.

---

<div class="post-metadata">

### Author: ![fedoroff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fedoroff/32/53209_2.png) [@fedoroff](https://discourse.julialang.org/u/fedoroff)
#### Post date: [September 4, 2022, 9:33am UTC](https://discourse.julialang.org/t/nonorthogonal-axes-in-makie-or-maybe-in-other-plotting-package/86749/3 "2022-09-04T09:33:05Z")

</div>

Thank you, but it is not exactly what I need. Of cause, as soon as you have an image, you can transform it as you like. Instead, I would like to have the original plot in these coordinates. It is especially important in 3D case, where I want to inspect the data by zooming, rotating, etc.

---

<div class="post-metadata">

### Author: ![BambOoxX](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bambooxx/32/22179_2.png) [@BambOoxX](https://discourse.julialang.org/u/BambOoxX)
#### Post date: [September 4, 2022, 10:50am UTC](https://discourse.julialang.org/t/nonorthogonal-axes-in-makie-or-maybe-in-other-plotting-package/86749/4 "2022-09-04T10:50:36Z")

</div>

In makie you can play with perspective in [Axis3](https://makie.juliaplots.org/v0.17.13/examples/blocks/axis3/index.html), I guess in Plots too (the contrary would be surprising). In a way this renders non orthogonal axes.  
Regarding your demand related to crystals, you could apply a back-transformation of the non-orthogonal crystal shape to an orthogonal one, plot it, then re-apply the transformation to get both axes and data in the desired shape.

A side note : `pgfplots` can handle such transformations (at least in 2d) see [pgfplots - Minkowski diagram non-orthogonal axis - TeX - LaTeX Stack Exchange](https://tex.stackexchange.com/questions/601977/minkowski-diagram-non-orthogonal-axis). Since its accessible in julia using [Home · PGFPlotsX.jl](https://kristofferc.github.io/PGFPlotsX.jl/stable/) you could try that.

---

<div class="post-metadata">

### Author: ![fedoroff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fedoroff/32/53209_2.png) [@fedoroff](https://discourse.julialang.org/u/fedoroff)
#### Post date: [September 4, 2022, 11:33am UTC](https://discourse.julialang.org/t/nonorthogonal-axes-in-makie-or-maybe-in-other-plotting-package/86749/5 "2022-09-04T11:33:11Z")

</div>

> In makie you can play with perspective in [Axis3](https://makie.juliaplots.org/v0.17.13/examples/blocks/axis3/index.html)

As with the image transformations, this approach is not dictated by the data one wish to plot.

> Regarding your demand related to crystals, you could apply a back-transformation of the non-orthogonal crystal shape to an orthogonal one

Yes, this I can do.

> then re-apply the transformation to get both axes and data in the desired shape

But how? I can re-apply the transformation, but the standard plotting functions, like `heatmap(x, y, values)` accept `x` and `y` coordinates assuming that they are defined in orthogonal Cartesian axes.

> `pgfplots` can handle such transformations (at least in 2d)

Yes, that is what I need. But I need it in an interactive regime to explore the data.

---

<div class="post-metadata">

### Author: ![BambOoxX](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bambooxx/32/22179_2.png) [@BambOoxX](https://discourse.julialang.org/u/BambOoxX)
#### Post date: [September 4, 2022, 11:51am UTC](https://discourse.julialang.org/t/nonorthogonal-axes-in-makie-or-maybe-in-other-plotting-package/86749/6 "2022-09-04T11:51:36Z")

</div>

> [@fedoroff](#):
>
> But how? I can re-apply the transformation, but the standard plotting functions, like `heatmap(x, y, values)` accept `x` and `y` coordinates assuming that they are defined in orthogonal Cartesian axes.

If you map the data to cartesian space, then you can use `heatmap` normally.

Another solution could be to not use `heatmap` or `image` altogether, but `poly` and `lines`… This way you can plot any group of polygons, here distorted pixels of diamond shape with their colors, as well as pseudo-axis lines. Anything of higher-level would not achieve what you want I believe.

---

<div class="post-metadata">

### Author: ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)
#### Post date: [September 4, 2022, 12:08pm UTC](https://discourse.julialang.org/t/nonorthogonal-axes-in-makie-or-maybe-in-other-plotting-package/86749/7 "2022-09-04T12:08:10Z")

</div>

For Makie, you can do it but it’s fully manual. An axis is just made out of plot objects, so you can draw whatever you want, including an oblique axis. But I assume your question was less about pure possibility, but if there’s something already implemented. To that, not yet, no.

---

<div class="post-metadata">

### Author: ![fedoroff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fedoroff/32/53209_2.png) [@fedoroff](https://discourse.julialang.org/u/fedoroff)
#### Post date: [September 4, 2022, 12:19pm UTC](https://discourse.julialang.org/t/nonorthogonal-axes-in-makie-or-maybe-in-other-plotting-package/86749/8 "2022-09-04T12:19:44Z")

</div>

If I will have to use some low level functions it is fine.  
Can you share any example with me?

---

<div class="post-metadata">

### Author: ![BambOoxX](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bambooxx/32/22179_2.png) [@BambOoxX](https://discourse.julialang.org/u/BambOoxX)
#### Post date: [September 5, 2022, 3:53pm UTC](https://discourse.julialang.org/t/nonorthogonal-axes-in-makie-or-maybe-in-other-plotting-package/86749/9 "2022-09-05T15:53:49Z")

</div>

It’s a very basic example but it shows you how to show an image as a non rectangular shape using `poly`

```julia
using GLMakie, FileIO

# load image, see Makie `image`
img = load(assetpath("cow.png"))
# Define pixel dimensions
wh = 1
ht = 1
# Define pixel shape here a rectangle
refdiamond = Point2f[(0,0), (wh,0), (wh,ht),(0,ht)]

# Start figure and axis
f = Figure()
ax = Axis(f[1,1])
# Compute all pixel positions
diamonds = [refdiamond .+ Point2f((i-1+j)*wh,(j-1)*ht) for i in axes(img,2) for j in axes(img,1)]
# Display the pixels using the colors in img
poly!(ax,diamonds,color = vec(img))
# Hide axes
hidedecorations!(ax)
f

```

 ![image](https://global.discourse-cdn.com/julialang/original/3X/d/4/d40f3832657fa236eca7320549e62e7ff7ace42c.jpeg)

---

<div class="post-metadata">

### Author: ![fedoroff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fedoroff/32/53209_2.png) [@fedoroff](https://discourse.julialang.org/u/fedoroff)
#### Post date: [September 5, 2022, 6:03pm UTC](https://discourse.julialang.org/t/nonorthogonal-axes-in-makie-or-maybe-in-other-plotting-package/86749/10 "2022-09-05T18:03:01Z")

</div>

Perfect! Thank you!  
`color = vec(img)` - this is kind of surprising

---

<div class="post-metadata">

### Author: ![BambOoxX](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bambooxx/32/22179_2.png) [@BambOoxX](https://discourse.julialang.org/u/BambOoxX)
#### Post date: [September 6, 2022, 7:28am UTC](https://discourse.julialang.org/t/nonorthogonal-axes-in-makie-or-maybe-in-other-plotting-package/86749/11 "2022-09-06T07:28:07Z")

</div>

> [@fedoroff](#):
>
> `color = vec(img)` - this is kind of surprising

Well an image is a matrix of color values, one per pixel, so `vec`ing it just allows to retrieve a vector or colors, 1 per diamond in `diamonds`

---

<div class="post-metadata">

### Author: ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)
#### Post date: [September 6, 2022, 1:12pm UTC](https://discourse.julialang.org/t/nonorthogonal-axes-in-makie-or-maybe-in-other-plotting-package/86749/12 "2022-09-06T13:12:15Z")

</div>

It’s probably also possible to do the shearing with a model transform instead of manually calculating it and using polys for each pixel.

---

<div class="post-metadata">

### Author: ![fedoroff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fedoroff/32/53209_2.png) [@fedoroff](https://discourse.julialang.org/u/fedoroff)
#### Post date: [September 7, 2022, 1:13pm UTC](https://discourse.julialang.org/t/nonorthogonal-axes-in-makie-or-maybe-in-other-plotting-package/86749/13 "2022-09-07T13:13:14Z")

</div>

The adapted code for arbitrary guiding vectors and with pixel shape correction:

```julia
import GLMakie as mak

# Data to plot:
xmin, xmax, Nx = -3, 3, 100
ymin, ymax, Ny = -3, 3, 200
x = range(xmin, xmax, length=Nx)
y = range(ymin, ymax, length=Ny)
img = @. exp(-(x * y')^2)

# Axes guiding vectors:
# a1, a2 = mak.Point2f(1,0), mak.Point2f(0,1)
# a1, a2 = mak.Point2f(2,1), mak.Point2f(1,2)
a1, a2 = mak.Point2f(1,-0.5), mak.Point2f(-0.5,1)

# normalize axes vectors:
a1 = a1 / sqrt(sum(abs2, a1))
a2 = a2 / sqrt(sum(abs2, a2))

# Define pixel:
dx = step(x)
dy = step(y)
dp = mak.Point2f(sqrt(dx*dy), sqrt(dx*dy))

# pixel = mak.Point2f[(0,0), (dp[1],0), (dp[1],dp[2]), (0,dp[2])] # square pixel
pixel = [mak.Point2f(0,0), dp*a1, dp*(a1+a2), dp*a2] # skew pixel

# Compute all pixel positions:
pixels = [
    pixel .+ ((i-1) * dp[1] * a1 + (j-1) * dp[2] * a2) for j=1:Ny for i=1:Nx
]

# Figure and axis:
fig = mak.Figure()
ax = mak.Axis(fig[1,1])
mak.hidedecorations!(ax)

# draw new axes:
xlen = 1.1 * (dp[1] * Nx)
ylen = 1.1 * (dp[2] * Ny)
O = mak.Point2f(0,0)
mak.lines!(ax, [O, O + xlen*a1]; color=:black)
mak.lines!(ax, [O, O + ylen*a2]; color=:black)
mak.text!(ax, mak.L"a_1"; position=O+xlen*a1, color=:black)
mak.text!(ax, mak.L"a_2"; position=O+ylen*a2, color=:black)

# draw the resulting heatmap:
mak.poly!(ax, pixels, color=vec(img))

fig

```

 ![right](https://global.discourse-cdn.com/julialang/original/3X/2/f/2f8792ec987858515b8c73a9c2a32c3910d1a446.png)  
 ![sharp](https://global.discourse-cdn.com/julialang/original/3X/2/1/21bac4d7f57c884ced6a53b8282a7dad14daf19f.png)  
 ![obtuse](https://global.discourse-cdn.com/julialang/original/3X/1/e/1e20b921d59de4aa644e05b5962a4c8310eb3b68.png)

😀

---

<div class="post-metadata">

### Author: ![fedoroff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fedoroff/32/53209_2.png) [@fedoroff](https://discourse.julialang.org/u/fedoroff)
#### Post date: [September 7, 2022, 1:20pm UTC](https://discourse.julialang.org/t/nonorthogonal-axes-in-makie-or-maybe-in-other-plotting-package/86749/14 "2022-09-07T13:20:19Z")

</div>

Now, can it be done in 3D in a similar manner for plotting of 3D arrays? What should be the corresponding 3D pixel?

---

<div class="post-metadata">

### Author: ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)
#### Post date: [September 7, 2022, 3:05pm UTC](https://discourse.julialang.org/t/nonorthogonal-axes-in-makie-or-maybe-in-other-plotting-package/86749/15 "2022-09-07T15:05:45Z")

</div>

You’d need to use `mesh` for that directly, instead of `poly`, because that one uses an algorithm to decompose to a mesh that works only in 2D.
