{"spec_id":"line-timeseries-rolling","library":"makie","language":"julia","code":"# anyplot.ai\n# line-timeseries-rolling: Time Series with Rolling Average Overlay\n# Library: makie 0.21.9 | Julia 1.11.9\n# Quality: 89/100 | Created: 2026-09-05\n\nusing CairoMakie\nusing Colors\nusing Random\nusing Statistics\nusing Dates\n\nRandom.seed!(42)\n\n# --- Theme tokens (see prompts/default-style-guide.md \"Theme-adaptive Chrome\") ---\nconst THEME       = get(ENV, \"ANYPLOT_THEME\", \"light\")\nconst PAGE_BG     = THEME == \"light\" ? colorant\"#FAF8F1\" : colorant\"#1A1A17\"\nconst ELEVATED_BG = THEME == \"light\" ? colorant\"#FFFDF6\" : colorant\"#242420\"\nconst INK         = THEME == \"light\" ? colorant\"#1A1A17\" : colorant\"#F0EFE8\"\nconst INK_SOFT    = THEME == \"light\" ? colorant\"#4A4A44\" : colorant\"#B8B7B0\"\nconst INK_MUTED   = THEME == \"light\" ? colorant\"#6B6A63\" : colorant\"#A8A79F\"\nconst BRAND       = colorant\"#009E73\"  # Imprint palette position 1 — ALWAYS first series\n\n# --- Data: SaaS product daily active users with a 30-day rolling average -------\nn_days = 220\nwindow = 30\nstart_date = Date(2024, 1, 1)\ndates = start_date .+ Day.(0:(n_days - 1))\nday_of_week = Dates.dayofweek.(dates)\n\ntrend = range(52.0, 84.0; length = n_days)\nweekend_dip = [dow in (6, 7) ? -6.0 : 0.0 for dow in day_of_week]\nnoise = randn(n_days) .* 3.5\ndaily_active_users = collect(trend) .+ weekend_dip .+ noise\n\nrolling_days = window:n_days\nrolling_avg = [mean(daily_active_users[(i - window + 1):i]) for i in rolling_days]\nrolling_std = [std(daily_active_users[(i - window + 1):i]) for i in rolling_days]\ngrowth_pct = round(Int, (rolling_avg[end] - rolling_avg[1]) / rolling_avg[1] * 100)\n\ntick_positions = collect(1:30:n_days)\nif tick_positions[end] != n_days\n    push!(tick_positions, n_days)\nend\ntick_labels = Dates.format.(dates[tick_positions], \"u dd\")\n\n# --- Plot ------------------------------------------------------------------\nfig = Figure(\n    size            = (1600, 900),\n    fontsize        = 14,\n    backgroundcolor = PAGE_BG,\n)\n\nax = Axis(\n    fig[1, 1];\n    title              = \"line-timeseries-rolling · julia · makie · anyplot.ai\",\n    titlesize          = 20,\n    titlecolor         = INK,\n    xlabel             = \"Date\",\n    ylabel             = \"Daily Active Users (thousands)\",\n    xlabelsize         = 14,\n    ylabelsize         = 14,\n    xlabelcolor        = INK,\n    ylabelcolor        = INK,\n    xticklabelsize     = 12,\n    yticklabelsize     = 12,\n    xticklabelcolor    = INK_SOFT,\n    yticklabelcolor    = INK_SOFT,\n    xtickcolor         = INK_SOFT,\n    ytickcolor         = INK_SOFT,\n    xticks             = (tick_positions, tick_labels),\n    backgroundcolor    = PAGE_BG,\n    topspinevisible    = false,\n    rightspinevisible  = false,\n    leftspinecolor     = INK_SOFT,\n    bottomspinecolor   = INK_SOFT,\n    xgridvisible       = true,\n    ygridvisible       = true,\n    xgridcolor         = RGBAf(INK.r, INK.g, INK.b, 0.15),\n    ygridcolor         = RGBAf(INK.r, INK.g, INK.b, 0.15),\n    xminorgridvisible  = false,\n    yminorgridvisible  = false,\n)\n\nband!(\n    ax, rolling_days, rolling_avg .- rolling_std, rolling_avg .+ rolling_std;\n    color = (BRAND, 0.12),\n)\nlines!(\n    ax, 1:n_days, daily_active_users;\n    color = (INK_MUTED, 0.55), linewidth = 1.5, label = \"Raw Data\",\n)\nlines!(\n    ax, rolling_days, rolling_avg;\n    color = BRAND, linewidth = 3.5, label = \"$(window)-Day Rolling Average\",\n)\nscatter!(ax, [rolling_days[end]], [rolling_avg[end]]; color = BRAND, markersize = 10, strokewidth = 0)\ntext!(\n    ax, rolling_days[end], rolling_avg[end];\n    text     = \"+$(growth_pct)% growth\",\n    color    = INK,\n    fontsize = 13,\n    font     = :bold,\n    align    = (:right, :bottom),\n    offset   = (-8, 10),\n)\n\naxislegend(\n    ax;\n    position        = :lt,\n    labelcolor      = INK,\n    backgroundcolor = ELEVATED_BG,\n    framevisible    = false,\n)\n\n# --- Save --------------------------------------------------------------------\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}