{"spec_id":"line-parametric","library":"letsplot","language":"python","code":"\"\"\" anyplot.ai\nline-parametric: Parametric Curve Plot\nLibrary: letsplot 4.10.1 | Python 3.13.14\nQuality: 90/100 | Updated: 2026-06-20\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nfrom lets_plot import *\n\n\nLetsPlot.setup_html()\n\n# Theme tokens — Imprint palette, theme-adaptive chrome\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nGRID_COLOR = \"#E3E2DB\" if THEME == \"light\" else \"#2A2A27\"\n\n# Imprint sequential colormap: brand green (t=0) → blue (t=max)\nGRAD_LOW = \"#009E73\"  # Imprint position 1 — first series / start\nGRAD_HIGH = \"#4467A3\"  # Imprint position 3 — end\n\n# Data — Lissajous figure: x = sin(3t), y = sin(2t), t ∈ [0, 2π]\nt_lissajous = np.linspace(0, 2 * np.pi, 1000)\ndf_lissajous = pd.DataFrame({\"x\": np.sin(3 * t_lissajous), \"y\": np.sin(2 * t_lissajous), \"t\": t_lissajous})\n\n# Data — Archimedean spiral: x = t·cos(t), y = t·sin(t), t ∈ [0, 4π]\nt_spiral = np.linspace(0, 4 * np.pi, 1000)\ndf_spiral = pd.DataFrame({\"x\": t_spiral * np.cos(t_spiral), \"y\": t_spiral * np.sin(t_spiral), \"t\": t_spiral})\n\nanyplot_theme = theme(\n    plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n    panel_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n    panel_grid_major=element_line(color=GRID_COLOR, size=0.4),\n    panel_grid_minor=element_blank(),\n    axis_title=element_text(size=12, color=INK),\n    axis_text=element_text(size=10, color=INK_SOFT),\n    axis_line=element_blank(),\n    axis_ticks=element_blank(),\n    plot_title=element_text(size=13, color=INK, face=\"bold\"),\n    legend_text=element_text(size=10, color=INK_SOFT),\n    legend_title=element_text(size=10, color=INK),\n    legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),\n)\n\n# Plot — Lissajous figure (closed curve: start ≡ end at origin, show only start)\nplot_lissajous = (\n    ggplot(df_lissajous, aes(x=\"x\", y=\"y\", color=\"t\"))\n    + geom_path(size=1.5, alpha=0.9, tooltips=layer_tooltips().line(\"t = @t\").format(\"t\", \".2f\"))\n    + geom_point(data=df_lissajous.iloc[[0]], mapping=aes(x=\"x\", y=\"y\"), color=GRAD_LOW, size=5, shape=16)\n    + scale_color_gradient(low=GRAD_LOW, high=GRAD_HIGH, name=\"t (rad)\", format=\".1f\")\n    + coord_fixed()\n    + labs(x=\"x(t) = sin(3t)\", y=\"y(t) = sin(2t)\", title=\"Lissajous Figure  ·  3:2 frequency ratio, closed\")\n    + anyplot_theme\n)\n\n# Plot — Archimedean spiral (open curve: show both start and end markers)\nplot_spiral = (\n    ggplot(df_spiral, aes(x=\"x\", y=\"y\", color=\"t\"))\n    + geom_path(size=1.5, alpha=0.9, tooltips=layer_tooltips().line(\"t = @t\").format(\"t\", \".2f\"))\n    + geom_point(data=df_spiral.iloc[[0]], mapping=aes(x=\"x\", y=\"y\"), color=GRAD_LOW, size=5, shape=16)\n    + geom_point(data=df_spiral.iloc[[-1]], mapping=aes(x=\"x\", y=\"y\"), color=GRAD_HIGH, size=5, shape=17)\n    + scale_color_gradient(low=GRAD_LOW, high=GRAD_HIGH, name=\"t (rad)\", format=\".1f\")\n    + coord_fixed()\n    + labs(x=\"x(t) = t·cos(t)\", y=\"y(t) = t·sin(t)\", title=\"Archimedean Spiral  ·  expanding outward\")\n    + anyplot_theme\n)\n\n# Side-by-side layout with overall title\ngrid_plot = gggrid([plot_lissajous, plot_spiral], ncol=2)\ntitle_str = \"line-parametric · python · letsplot · anyplot.ai\"\nfinal_plot = (\n    grid_plot\n    + ggsize(800, 450)\n    + ggtitle(title_str)\n    + theme(\n        plot_title=element_text(size=16, color=INK, face=\"bold\"),\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n    )\n)\n\n# Save PNG and interactive HTML\nggsave(final_plot, f\"plot-{THEME}.png\", path=\".\", scale=4)\nggsave(final_plot, f\"plot-{THEME}.html\", path=\".\")\n"}