When I create a 3D scatter plot in Makie some of the points that are “closer” to the camera are plotted behind points that are further from the camera. This can make the plots harder to interpret. Is there a setting or technique to change or improve this behavior?
The below image shows what I mean where some points that are higher on the z-axis and therefore closer to the camera (lighter color)are plotted behind points that are lower down and further from the camera.
Try the following little code. I have added an annotation that points to a specific example and this should be reproducible (although I’m not familiar with the details of seeding the RNG across julia versions/platforms. This was using Julia Version 1.8.5 on Windows).
using CairoMakie, Random
#Seed RNG
Random.seed!(21)
#Create Random Points
x = rand(1000)
y = rand(1000)
z = rand(1000)
#plot aligned along z-axis (higher Z is closer to camera)
fig = Figure()
ax1=Axis3(fig[1, 1], aspect=:data, azimuth = 0,elevation=2pi/4)
scatter!(x,y,z,color = z)
ax1.xlabel = "X"
ax1.ylabel = "Y"
ax1.zlabel = "Z"
#annotate a specific example
text!(1,0.95,1,text="←",color=:red,fontsize=24)
fig
This produces the below plot (in Pluto. Not sure how to pop up a plot viewer or save the figure from the REPL, I’m looking into it). It is a 3D scatter plot that where the camera is aligned with the z-axis. Higher Z is closer to the camera. Points are colored by Z position so we know that a lighter colored point is closer to the camera than a darker colored point. Nonetheless in this example (and indeed if you look a bit I can find several examples for any given seed) there is a darker colored point painted over the top of a lighter colored point.
I believe this is a limitation of the Cairo backend:
CairoMakie as a 2D engine has no concept of z-clipping, therefore its 3D capabilities are quite limited. The z-values of 3D plots will have no effect and will be projected flat onto the canvas. Z-layering is approximated by sorting all plot objects by their z translation value before drawing, after that by parent scene and then insertion order. Therefore, if you want to draw something on top of something else, but it ends up below, try translating it forward via translate!(obj, 0, 0, some_positive_z_value).
In the toy example sorting by z value is pretty easy if it fixes the problem. In the general case where the camera is not aligned with an axis it would be a lot trickier (but not impossible I’m fairly certain).
Well you’d have to specify the axis from which the plots perspective should be, but if you have it the z order should just be the value of the data points projection into the axis right?
I.e.
axis = [1,1,1]
point = [x,y,z]
zorder = point'*axis
And so on.
(Cannot try it out right now but this should do the trick)
Sorry for resurrecting this old(ish) thread, but I was trying to apply the solution to a plot consisting of multiple line, where each line is associated with some value that I want to sort the lines according to. The attached image shows what this looks like.
The color of each line indicates the sorting, and I would like the dark blue lines to be in front, and the yellow lines at the back. However, the order appears to be jumbled up.
I know I can achieve this in GLMakie, but the CairoMakie figure looks so much nicer.
I guess my question is what part of each line is used for determining the drawing order? I tried drawing the lines in the order dictated by the color, but that didn’t seem to help; the order was still scrambled. I also tried applying the z-order transform in the solution to OPs original question, but it wasn’t clear to me what point to use for each line.
CairoMakie sorts by z component of the transformation, not at all by data coordinates. So if you plot all the lines in back to front order it should look correct. Unless the sorting somehow doesn’t respect the original order if the transformation components are the same (0 if unset)
Thanks a lot, that worked. Somehow I had the impression that the lines should be plotted from front to back, which in hindsight doesn’t make sense. Plotting them back to front worked perfectly.