Replacing only the data layer of points in a Makie figure with protrusions

I have a plot that requires a lot of code to create protrusions. So, it would be nice to just replace the data layer of the plot without messing with the protrusions. Is this possible?

I have example code here:

using DataFrames, CairoMakie, AlgebraOfGraphics, 
CairoMakie.activate!(type = "svg") # crisper plots than default png
set_aog_theme!() # color-blind friendly colors
update_theme!(fontsize = 20) # larger font size

## create two points to plot
df = DataFrame(x = [0.9,0.8], y = [0.9,0.8])  

## plot two points
dfMapping = mapping(:x, :y) * 
            visual(color = :darkblue, 
                markersize = 24)
dfLayer = data(df) * dfMapping
draw(dfLayer, axis = (limits = (0,1,0,1),))

## create protrusions
topDF =   DataFrame(x = 0:0.001:1,
                    y = 0:0.001:1)
rightDF = DataFrame(x = 0:0.001:1,
                    y = 1:-0.001:0)
topLayer = data(topDF) * mapping(:x,:y) * visual(Lines)
rightLayer = data(rightDF) * mapping(:x,:y) * visual(Lines)
## create empty canvas to plot into
marginPlot = Figure()
draw!(marginPlot[1,1],dfLayer, axis = (limits = (0,1,0,1),))

## place protrusions in figure 1
rightMarginAxis = Axis(marginPlot[1,1, Right()], 
                        width  = 100,
                        limits = (nothing,(0,1)))
topMarginAxis = Axis(marginPlot[1,1, Top()], 
                        height  = 100, 
                        limits = ((0,1),nothing))
hidedecorations!(rightMarginAxis)
hidespines!(rightMarginAxis)
hidedecorations!(topMarginAxis)
hidespines!(topMarginAxis)
draw!(rightMarginAxis, topLayer)
draw!(topMarginAxis, rightLayer)
marginPlot

## update data
push!(df, [0.2,0.2])

## update plot layer
dfLayer = data(df) * dfMapping

## update marginPlot
draw!(marginPlot[1,1],dfLayer, axis = (limits = (0,1,0,1),))
marginPlot


## can I now keep protrusions and axes, but plot only new data
newDF = DataFrame(x = 0.5, y = 0.5)
newLayer = data(newDF) * dfMapping * visual(Scatter, color = :darkorange)

draw!(marginPlot[1,1], newLayer, axis = (limits = (0,1,0,1),))
marginPlot 

## in other words, how to remove the blue dots from pic?
delete!(marginPlot[1,1]) ## gives method error

which generates the following plot:

BUT, what I really want is just the orange dot and not the blue dots. How would I do this? Thx!

I’m sorry, I don’t understand the problem. Why are you plotting the blue points in the first place? What are the lines at the sides supposed to be?

Thanks for looking at it. This is a simplified version of my true goal of demonstrating MCMC Burn-In. I first plot all points (blue ones as part of burn-in and orange as part of post burn-in sampling) and then, I seek to remove the blue dots (i.e. use a different underlying dataframe) without messing with the protrusions. In my real-problem, the protrusions will show target marginal density functions, not silly lines.

In my real-problem (pic below), I want to go from the plot on the left to the plot on the right (without the original points from the left-plot) where the only thing that changes is the dataframe underlying the blue points. Unfortunately, the plot on the right still shows the previous points.

Ok, so you need the intermediate version with the orange dots for something else and then want to save another version where they are removed? You can delete plots from axes with the delete! function but it would be a bit fiddly maybe to get the plot objects from your AlgebraOfGraphics output. It seems to me that your plot is so simple that AoG is kind of overkill for it, or do you have other reasons to use it for this?

1 Like

Thanks for the guidance.

It is definitely fiddly in AoG land (so fiddly, I cannot figure it out). The reason for AoG is that I am a big believer in the grammar of graphics. For me, it is conceptually easier to break the plotting process into data (from a DataFrame), mappings, visual markings, and axes. Additionally, AoG is cleaner for DataFrame-originated workflows whereas if you look through the Makie.jl documentation, all workflows start from data generated from a function. I have been trying to use AoG as a complete Makie substitute - akin to ggplot2 in R, but am discovering that this is not really feasible at the moment and Makie has some really nice layout features that I want to take advantage of.

My opinion is that grammar-of-graphics approaches are nice for a lot of “basic” things, and they do save time when labelling axes, creating legends, etc. Especially if that kind of metadata is already available through column headers.

But as soon as you step off this “cartesian-product” path, where everything is nicely balanced, it tends to get worse to manipulate the output of a grammar-of-graphics plot so that it conforms to these needs. At least that’s my experience.

Such things include (but are not limited to): Uneven or missing axes in grids, partial merging of legends, leaving out or adding arbitrary legend entries, removing axis labels in only some cases, partial linking of axes, cross-axis annotations, etc etc. So my goal is to help AlgebraOfGraphics to make the going back and forth between it and Makie as painless as possible. Then hopefully the grammar of graphics approach will build the base layer for many people with common scenarios, and the rest can be done imperatively. It is already pretty much possible, but as you note, fiddly.

1 Like

I would also agree with the idea that, even though it’d be conceptually clearer to do everything with the same syntax, it’s probably more reasonable to switch to Makie as soon as it gets too specific for AlgebraOfGraphics.

For instance in this case, I think it’s reasonable to start with

f = Figure()
ax1, ax2 = Axis(f[1, 1]), Axis(f[1, 2])
plt = mapping(...) * visual(...) # your plot specification
draw!(ax1, data(df1) * plt)
draw!(ax2, data(df2) * plt)

And then proceed to add protrusions with plain Makie code (especially because it looks like those are theoretical predictions, so they don’t depend on any data and AoG wouldn’t help much).

1 Like