{"spec_id":"quiver-basic","library":"makie","language":"julia","code":"# anyplot.ai\n# quiver-basic: Basic Quiver Plot\n# Library: makie 0.21.9 | Julia 1.11.9\n# Quality: 89/100 | Created: 2026-07-24\n\nusing CairoMakie\nusing Colors\nusing Random\n\nRandom.seed!(42)\n\n# --- Theme tokens -----------------------------------------------------------\nconst THEME    = get(ENV, \"ANYPLOT_THEME\", \"light\")\nconst PAGE_BG  = THEME == \"light\" ? colorant\"#FAF8F1\" : colorant\"#1A1A17\"\nconst INK      = THEME == \"light\" ? colorant\"#1A1A17\" : colorant\"#F0EFE8\"\nconst INK_SOFT = THEME == \"light\" ? colorant\"#4A4A44\" : colorant\"#B8B7B0\"\n\n# Imprint sequential colormap — magnitude is single-polarity (speed >= 0)\nconst IMPRINT_SEQ = [colorant\"#009E73\", colorant\"#4467A3\"]\n\n# --- Data: cyclonic vortex wind field ---------------------------------------\n# Rankine vortex: solid-body rotation inside the eyewall (speed rises with r),\n# then decays with 1/r outside it. v_max=33 m/s matches the Category-1\n# hurricane threshold, so the field genuinely mirrors a real cyclone's wind\n# profile rather than a gentle breeze.\nnx, ny = 20, 12\nxs = range(-8.0, 8.0; length = nx)\nys = range(-4.5, 4.5; length = ny)\n\nx = vec([xi for xi in xs, yi in ys])\ny = vec([yi for xi in xs, yi in ys])\n\nr = sqrt.(x .^ 2 .+ y .^ 2)\ntheta = atan.(y, x)\ncore_radius = 3.0\nv_max = 33.0\nspeed = ifelse.(r .<= core_radius, v_max .* r ./ core_radius, v_max .* core_radius ./ max.(r, 1e-6))\n\n# Floor the *displayed* arrow length (not the true speed) so the 1-2 grid\n# points nearest the calm core never shrink to invisible slivers; color still\n# maps to the true, unfloored speed.\nmin_display_speed = 0.18 * v_max\ndisplay_speed = max.(speed, min_display_speed)\nu = -display_speed .* sin.(theta)\nv = display_speed .* cos.(theta)\n\n# --- Plot ---------------------------------------------------------------\nfig = Figure(resolution = (1600, 900), fontsize = 14, backgroundcolor = PAGE_BG)\n\nax = Axis(\n    fig[1, 1];\n    title = \"quiver-basic · julia · makie · anyplot.ai\",\n    titlesize = 20,\n    titlecolor = INK,\n    xlabel = \"X position (km)\",\n    ylabel = \"Y position (km)\",\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    backgroundcolor = PAGE_BG,\n    topspinevisible = false,\n    rightspinevisible = false,\n    leftspinecolor = INK_SOFT,\n    bottomspinecolor = INK_SOFT,\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    aspect = DataAspect(),\n)\n\n# Subtle dashed ring at the eyewall radius -- the band of peak wind speed --\n# drawn beneath the arrows to sharpen the storytelling without competing\n# with the vector field itself.\neyewall_theta = range(0, 2 * pi; length = 100)\nlines!(\n    ax,\n    core_radius .* cos.(eyewall_theta),\n    core_radius .* sin.(eyewall_theta);\n    color = RGBAf(INK_SOFT.r, INK_SOFT.g, INK_SOFT.b, 0.35),\n    linestyle = :dash,\n    linewidth = 1.2,\n)\n\narrow_plot = arrows!(\n    ax,\n    x,\n    y,\n    u,\n    v;\n    arrowsize = 14,\n    lengthscale = 0.025,\n    linewidth = 2.5,\n    color = speed,\n    colormap = IMPRINT_SEQ,\n)\n\nColorbar(\n    fig[1, 2],\n    arrow_plot;\n    label = \"Wind speed (m/s)\",\n    labelcolor = INK,\n    labelsize = 14,\n    ticklabelsize = 13,\n    ticklabelcolor = INK_SOFT,\n    tickcolor = INK_SOFT,\n)\n\nxlims!(ax, -9, 9)\nylims!(ax, -5.5, 5.5)\n\ncolsize!(fig.layout, 1, Relative(0.88))\n\n# --- Save --------------------------------------------------------------\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}