{"spec_id":"line-parametric","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\nline-parametric: Parametric Curve Plot\nLibrary: plotnine 0.15.7 | Python 3.13.14\nQuality: 93/100 | Updated: 2026-06-20\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nfrom plotnine import (\n    aes,\n    coord_equal,\n    element_blank,\n    element_line,\n    element_rect,\n    element_text,\n    facet_wrap,\n    geom_path,\n    geom_point,\n    ggplot,\n    guide_colorbar,\n    guide_legend,\n    guides,\n    labs,\n    scale_color_gradientn,\n    scale_fill_manual,\n    scale_shape_manual,\n    theme,\n    theme_void,\n)\n\n\n# Theme tokens\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\"\n\n# Imprint sequential colormap — brand green → blue (single-polarity, direction of t)\nIMPRINT_SEQ = [\"#009E73\", \"#4467A3\"]\n\n# Marker fills from Imprint palette: green = start (matches gradient low), red = end (contrast)\nMARKER_START = \"#009E73\"  # brand green\nMARKER_END = \"#AE3030\"  # matte red — semantic contrast against blue path end\n\n# Data — normalize t to [0, 1] per curve so both panels use the full color gradient\nn_points = 1000\nt_lissajous = np.linspace(0, 2 * np.pi, n_points)\nx_lissajous = np.sin(3 * t_lissajous)\ny_lissajous = np.sin(2 * t_lissajous)\nt_norm_liss = np.linspace(0, 1, n_points)\n\nt_spiral = np.linspace(0, 4 * np.pi, n_points)\nx_spiral = t_spiral * np.cos(t_spiral) / (4 * np.pi)\ny_spiral = t_spiral * np.sin(t_spiral) / (4 * np.pi)\nt_norm_spiral = np.linspace(0, 1, n_points)\n\ndf = pd.concat(\n    [\n        pd.DataFrame(\n            {\"x\": x_lissajous, \"y\": y_lissajous, \"t_norm\": t_norm_liss, \"curve\": \"Lissajous · x = sin(3t), y = sin(2t)\"}\n        ),\n        pd.DataFrame(\n            {\"x\": x_spiral, \"y\": y_spiral, \"t_norm\": t_norm_spiral, \"curve\": \"Spiral · x = t·cos(t), y = t·sin(t)\"}\n        ),\n    ],\n    ignore_index=True,\n)\n\n# Start and end markers for direction cues\nmarkers = pd.concat(\n    [\n        pd.DataFrame(\n            {\n                \"x\": [x_lissajous[0], x_spiral[0]],\n                \"y\": [y_lissajous[0], y_spiral[0]],\n                \"curve\": [\"Lissajous · x = sin(3t), y = sin(2t)\", \"Spiral · x = t·cos(t), y = t·sin(t)\"],\n                \"endpoint\": [\"Start (t = 0)\", \"Start (t = 0)\"],\n            }\n        ),\n        pd.DataFrame(\n            {\n                \"x\": [x_lissajous[-1], x_spiral[-1]],\n                \"y\": [y_lissajous[-1], y_spiral[-1]],\n                \"curve\": [\"Lissajous · x = sin(3t), y = sin(2t)\", \"Spiral · x = t·cos(t), y = t·sin(t)\"],\n                \"endpoint\": [\"End (t = tmax)\", \"End (t = tmax)\"],\n            }\n        ),\n    ],\n    ignore_index=True,\n)\n\n# Plot\nplot = (\n    ggplot(df, aes(x=\"x\", y=\"y\", color=\"t_norm\"))\n    + geom_path(aes(group=\"curve\"), size=1.0, alpha=0.94)\n    + geom_point(\n        aes(shape=\"endpoint\", fill=\"endpoint\"), data=markers, color=INK, size=3.5, stroke=0.8, show_legend=True\n    )\n    + scale_shape_manual(name=\"Direction\", values={\"Start (t = 0)\": \"o\", \"End (t = tmax)\": \"D\"})\n    + scale_fill_manual(name=\"Direction\", values={\"Start (t = 0)\": MARKER_START, \"End (t = tmax)\": MARKER_END})\n    + facet_wrap(\"curve\", scales=\"free\")\n    + scale_color_gradientn(\n        name=\"Parameter t\",\n        colors=IMPRINT_SEQ,\n        breaks=[0.0, 0.25, 0.5, 0.75, 1.0],\n        labels=[\"0\", \"¼\", \"½\", \"¾\", \"tmax\"],\n        guide=guide_colorbar(nbin=200),\n    )\n    + coord_equal()\n    + labs(\n        title=\"line-parametric · python · plotnine · anyplot.ai\",\n        x=\"Horizontal Position  x(t)\",\n        y=\"Vertical Position  y(t)\",\n    )\n    + guides(shape=guide_legend(order=2), fill=guide_legend(order=2))\n    + theme_void()\n    + theme(\n        figure_size=(8, 4.5),\n        plot_title=element_text(size=12, weight=\"bold\", color=INK, margin={\"b\": 8}),\n        axis_title_x=element_text(size=10, color=INK, margin={\"t\": 6}),\n        axis_title_y=element_text(size=10, color=INK, margin={\"r\": 6}),\n        axis_text=element_text(size=8, color=INK_SOFT),\n        axis_ticks=element_blank(),\n        legend_title=element_text(size=8, weight=\"bold\", color=INK),\n        legend_text=element_text(size=8, color=INK_SOFT),\n        legend_key=element_rect(fill=ELEVATED_BG, color=ELEVATED_BG),\n        legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT, size=0.3),\n        legend_box_margin=4,\n        strip_text=element_text(size=9, weight=\"bold\", color=INK, margin={\"b\": 6}),\n        strip_background=element_rect(fill=ELEVATED_BG, color=\"none\"),\n        panel_spacing_x=0.1,\n        panel_grid_major=element_line(color=INK, size=0.2, alpha=0.15),\n        panel_grid_minor=element_blank(),\n        panel_background=element_rect(fill=PAGE_BG, color=\"none\"),\n        plot_background=element_rect(fill=PAGE_BG, color=\"none\"),\n        plot_margin=0.01,\n    )\n)\n\n# Save\nplot.save(f\"plot-{THEME}.png\", dpi=400, width=8, height=4.5, units=\"in\", verbose=False)\n"}