Hi,
This post is about plotting with Makie. I quite often set out making a figure and then later add further plots or labels. My workflow below works but seems a bit cumbersome to me and I would like to have your input on what a more Julia-like workflow would be like.
Many thanks,
Michael
# Step 1: first plot
f, ax, l1 = lines(1..10, sin; linestyle=:dashdot, color=:tomato, label="sin" )
# Set labels and title
ax.title = "my title"
ax.subtitle = "my subtitle"
ax.xlabel="x-label"
ax.ylabel="y-label"
f # display
Question 1: I didn’t find a way to directly pass the title and label to the lines
function (e.g. as keywords). Is this indeed not possible and the above code is the way to do it?
# Step 2: add an additional plot
lines!(ax, 1..10, cos; color=:blue, label="cos")
# I now would like to change attributes of the lines but I forgot to
# catch the plotobject.
# I can access it via the Axis object.
ax.scene.plots # all plot objects in the scene of the axis
@assert ax.scene.plots[2] == l1 # this is the first plot added
l2 = ax.scene.plots[3];
l2.attributes # list attributes
l2.color = :green # change it from blue to green
l2.label = "cos fun" # update label
f
Question 2: Do I need to go via ax.scene.plots
? It seems complicated and I wonder whether there is a simpler way? I tried ax.content
, similar to f.content
(where f
is a figure object) but this didn’t work.
# Step 3: add xticklabels
ax.xticks = [0, π, 2π, 3π] # set ticks
f
ax.xtickformat = x->["0", "Ď€", "2Ď€", "3Ď€"]; # set tick labels
f
Question 3: Is this the simplest way to set custom tick labels? I was looking for an option like ax.xticklabels = ["0", "Ď€", "2Ď€", "3Ď€"]
but didn’t find it.
# Step 4: add legend
axislegend("Legend title", position = :rb, orientation = :horizontal)
f
# not quite what I wanted. Let's add it on the outside
Legend(f[2,1], ax, "Trig functions")
# Oh, no. I again forgot to bind the Legend objects.
# I can access them via the figure object
#
leg2 = f.content[3]
leg1 = f.content[2]
@assert ax == f.content[1]
# fix spacing
f
leg2.tellwidth = false
leg2.tellheight = true
leg2.orientation = :horizontal
f
# remove first legend
delete!(leg1)
f
Question 4 For figures, I can quite intuitively access its objects, the axis and the two legends via f.content
. But for the axis object ax, I have to access
the plotting objects in a slightly convoluted way via ax.scene.plot
. What is the rationale here?
Question 5 Removing the first legend via delete!(leg1)
works in the sense that the legend is not displayed in the figure. But julia throws the error
ERROR: MethodError: no method matching remove_from_gridlayout!(::Nothing)
Closest candidates are:
remove_from_gridlayout!(::GridLayoutBase.GridContent) at ~/.julia/packages/GridLayoutBase/lYdxT/src/gridlayout.jl:290
Stacktrace:
[1] delete!(block::Legend)
@ Makie ~/.julia/packages/Makie/Ppzqh/src/makielayout/blocks.jl:503
[2] top-level scope
@ ...
and f.content
still lists two legend objects.
julia> f.content
3-element Vector{Any}:
Axis (3 plots)
Legend()
Legend()
How do I correctly delete the first legend object?