Smoothing over date axis in AlgebraOfGraphics

I have a bunch of observations (date on x-axis, weight on y-axis) that I want to plot a trend line through. Using DataFrames and AlgebraOfGraphics I can plot the individual points:

using AlgebraOfGraphics
using CairoMakie
using DataFrames
using Dates
dates = as_date.(["15/05", "18/05", "25/05", "31/05", "09/06", 
        "15/06", "24/06", "07/07", "15/07", "01/08", "18/08", 
        "01/09", "20/09", "28/09", "05/10", "17/10", "08/11", "17/11", "23/11"])
weights = [21.8, 22.5, 21.4, 21.8, 22.2, 22.6, 21.8, 22.8, 23.4, 22.9, 22.9, 22.7, 21.8, 22.3, 22.2, 22.0, 21.7, 21.7, 20.8]
df = DataFrame(dates=dates, weights=weights)
data(df) * mapping(:dates, :weights) |> draw

I can’t apply smoothing directly - because the loess() function in smooth() needs both x and y to be convertible to Float64 and my x axis is dates, but I can convert the a-axis to “days since start” and apply smoothing to that:

days(d) = Dates.value(d - dates[1]) |> Float64
data(df) * mapping(:dates => days => :days, :weights) * smooth()  |> draw

How do I overlay the smooth line over the points plot, so that the created plot has dates on the x-axis? (or to put it another way, add two layers that have different mappings for the x axis)

thanks,
Steve

Hi! So, it is slightly tricky, but it is possible using the internal function that converts dates to floats before plotting. So, you could do:

using AlgebraOfGraphics: datetime2float, datetimeticks
# Convert all to floats beforehand
plt = data(df) *  mapping(:dates => datetime2float, :weights) * (visual(Scatter) + smooth())
# Create the correct date ticks with `datetimeticks`
draw(plt, axis=(xticks=datetimeticks(string, dates[1:5:end]),))

What you wanted to do (have separate x values for different layers) is in theory possible with

plt = data(df) * (
    mapping(:dates, :weights) + # use dates here
    mapping(:dates => datetime2float, :weights) * smooth() # use floats here
)

but at the moment having different types of axes (numeric versus dates) in different layers errors (the above won’t work), though it could probably be fixed.

EDIT: ups, yes, fixed typo above

that solved it, thanks! The variation that worked for me is:

using AlgebraOfGraphics
using AlgebraOfGraphics: datetime2float
using CairoMakie
ax = (xticks=datetimeticks(string, dates[1:5:end]),)
plt = data(df) *  mapping(:dates => datetime2float, :weights) * (visual(Scatter) + smooth())
draw(plt; axis=ax)