{"spec_id":"lightcurve-transit","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nlightcurve-transit: Astronomical Light Curve\nLibrary: matplotlib 3.11.0 | Python 3.13.14\nQuality: 91/100 | Updated: 2026-06-20\n\"\"\"\n\nimport os\nimport sys\n\n\n# Prevent this file (matplotlib.py) from shadowing the matplotlib package\n_d = os.path.dirname(os.path.abspath(__file__))\nwhile _d in sys.path:\n    sys.path.remove(_d)\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib import patheffects\nfrom matplotlib.patches import FancyArrowPatch\nfrom matplotlib.ticker import FormatStrFormatter\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\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\n# Imprint palette — position 1 for photometry, position 3 for transit model\nBRAND = \"#009E73\"  # Imprint position 1 — photometry data\nMODEL_COLOR = \"#4467A3\"  # Imprint position 3 — transit model curve\n\n# Data\nnp.random.seed(42)\n\ntransit_center = 0.5\ntransit_duration = 0.08\ntransit_depth = 0.01\nu1, u2 = 0.3, 0.1\nhalf_dur = transit_duration / 2.0\nn_points = 500\n\n# Phase-folded observations\nphase = np.sort(np.random.uniform(0.0, 1.0, n_points))\n\n# Quadratic limb-darkened transit model for observations\nmodel_flux = np.ones(n_points)\nin_transit = np.abs(phase - transit_center) < half_dur\nz = np.abs(phase[in_transit] - transit_center) / half_dur\nlimb = 1.0 - u1 * (1 - np.sqrt(1 - z**2)) - u2 * (1 - np.sqrt(1 - z**2)) ** 2\nmodel_flux[in_transit] = 1.0 - transit_depth * limb\n\n# Simulated photometry with realistic noise\nflux_err = np.random.uniform(0.0008, 0.0020, n_points)\nflux = model_flux + np.random.normal(0, 1, n_points) * flux_err\n\n# Smooth model curve for overlay\nphase_smooth = np.linspace(0.0, 1.0, 2000)\nmodel_smooth = np.ones(2000)\nin_transit_s = np.abs(phase_smooth - transit_center) < half_dur\nz_s = np.abs(phase_smooth[in_transit_s] - transit_center) / half_dur\nlimb_s = 1.0 - u1 * (1 - np.sqrt(1 - z_s**2)) - u2 * (1 - np.sqrt(1 - z_s**2)) ** 2\nmodel_smooth[in_transit_s] = 1.0 - transit_depth * limb_s\n\n# Two-panel layout: full light curve + transit zoom (landscape 3200×1800)\nfig, (ax, ax_zoom) = plt.subplots(\n    1, 2, figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG, gridspec_kw={\"width_ratios\": [3, 1.2], \"wspace\": 0.15}\n)\nax.set_facecolor(PAGE_BG)\nax_zoom.set_facecolor(PAGE_BG)\n\n# === Main panel: full light curve ===\n\nout_mask = ~in_transit\nax.errorbar(\n    phase[out_mask],\n    flux[out_mask],\n    yerr=flux_err[out_mask],\n    fmt=\"o\",\n    markersize=2.5,\n    color=BRAND,\n    ecolor=BRAND,\n    elinewidth=0.7,\n    alpha=0.55,\n    markeredgecolor=PAGE_BG,\n    markeredgewidth=0.3,\n    capsize=0,\n    zorder=2,\n    label=\"Photometry\",\n)\nax.errorbar(\n    phase[in_transit],\n    flux[in_transit],\n    yerr=flux_err[in_transit],\n    fmt=\"o\",\n    markersize=3.5,\n    color=BRAND,\n    ecolor=BRAND,\n    elinewidth=0.7,\n    alpha=0.9,\n    markeredgecolor=PAGE_BG,\n    markeredgewidth=0.3,\n    capsize=0,\n    zorder=4,\n)\n\ntransit_mask_smooth = np.abs(phase_smooth - transit_center) < half_dur\nax.plot(phase_smooth, model_smooth, color=MODEL_COLOR, linewidth=1.8, zorder=5, label=\"Transit model\")\nax.fill_between(\n    phase_smooth[transit_mask_smooth], 1.0, model_smooth[transit_mask_smooth], color=MODEL_COLOR, alpha=0.08, zorder=1\n)\nax.axhline(y=1.0, color=INK_MUTED, linewidth=0.8, linestyle=\"--\", alpha=0.5, zorder=1)\n\n# Ingress/egress contact markers\nt1 = transit_center - half_dur\nt4 = transit_center + half_dur\nfor t_val, label in [(t1, \"$t_1$\"), (t4, \"$t_4$\")]:\n    ax.axvline(x=t_val, color=INK_MUTED, linewidth=0.6, linestyle=\":\", alpha=0.6, zorder=1)\n    ax.text(t_val, 1.0055, label, fontsize=9, color=INK_MUTED, ha=\"center\", va=\"bottom\")\n\nax.axvspan(transit_center - half_dur * 1.8, transit_center + half_dur * 1.8, color=BRAND, alpha=0.04, zorder=0)\n\nax.set_xlabel(\"Orbital Phase\", fontsize=10, color=INK)\nax.set_ylabel(\"Relative Flux\", fontsize=10, color=INK)\nax.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT, length=0)\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nfor s in (\"left\", \"bottom\"):\n    ax.spines[s].set_color(INK_SOFT)\nax.yaxis.grid(True, alpha=0.15, linewidth=0.6, color=INK)\nax.set_xlim(0.0, 1.0)\n\nax.xaxis.set_major_formatter(FormatStrFormatter(\"%.2f\"))\n\nleg = ax.legend(fontsize=8, frameon=True, loc=\"upper right\")\nif leg:\n    leg.get_frame().set_facecolor(ELEVATED_BG)\n    leg.get_frame().set_edgecolor(INK_SOFT)\n    plt.setp(leg.get_texts(), color=INK_SOFT)\n\n# === Zoom panel: transit detail ===\n\nax_zoom.errorbar(\n    phase[in_transit],\n    flux[in_transit],\n    yerr=flux_err[in_transit],\n    fmt=\"o\",\n    markersize=3.5,\n    color=BRAND,\n    ecolor=BRAND,\n    elinewidth=0.7,\n    alpha=0.9,\n    markeredgecolor=PAGE_BG,\n    markeredgewidth=0.3,\n    capsize=0,\n    zorder=4,\n)\nnear_mask = (np.abs(phase - transit_center) < half_dur * 2.0) & ~in_transit\nax_zoom.errorbar(\n    phase[near_mask],\n    flux[near_mask],\n    yerr=flux_err[near_mask],\n    fmt=\"o\",\n    markersize=2.5,\n    color=BRAND,\n    ecolor=BRAND,\n    elinewidth=0.7,\n    alpha=0.55,\n    markeredgecolor=PAGE_BG,\n    markeredgewidth=0.3,\n    capsize=0,\n    zorder=2,\n)\n\nzoom_phase = phase_smooth[transit_mask_smooth]\nzoom_model = model_smooth[transit_mask_smooth]\nax_zoom.plot(zoom_phase, zoom_model, color=MODEL_COLOR, linewidth=1.8, zorder=5)\nax_zoom.fill_between(zoom_phase, 1.0, zoom_model, color=MODEL_COLOR, alpha=0.10, zorder=1)\nax_zoom.axhline(y=1.0, color=INK_MUTED, linewidth=0.8, linestyle=\"--\", alpha=0.5)\n\n# Transit depth annotation with double-headed arrow\nmin_model = zoom_model.min()\narrow = FancyArrowPatch(\n    (transit_center - half_dur * 1.6, 1.0),\n    (transit_center - half_dur * 1.6, min_model),\n    arrowstyle=\"<->\",\n    color=MODEL_COLOR,\n    linewidth=1.2,\n    mutation_scale=8,\n    zorder=6,\n)\nax_zoom.add_patch(arrow)\ndf_text = ax_zoom.text(\n    transit_center - half_dur * 1.5,\n    (1.0 + min_model) / 2,\n    f\"$\\\\Delta F = {transit_depth * 100:.1f}\\\\%$\",\n    fontsize=10,\n    color=MODEL_COLOR,\n    va=\"center\",\n    ha=\"left\",\n    fontweight=\"bold\",\n    zorder=6,\n)\ndf_text.set_path_effects([patheffects.withStroke(linewidth=3, foreground=PAGE_BG), patheffects.Normal()])\n\nfor t_val, label in [(t1, \"$t_1$\"), (t4, \"$t_4$\")]:\n    ax_zoom.axvline(x=t_val, color=INK_MUTED, linewidth=0.6, linestyle=\":\", alpha=0.6, zorder=1)\n    ax_zoom.text(t_val, 1.004, label, fontsize=9, color=INK_MUTED, ha=\"center\", va=\"bottom\")\n\nzoom_margin = half_dur * 2.0\nax_zoom.set_xlim(transit_center - zoom_margin, transit_center + zoom_margin)\nax_zoom.set_ylim(min_model - 0.002, 1.006)\nax_zoom.set_xlabel(\"Orbital Phase\", fontsize=10, color=INK)\nax_zoom.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT, length=0)\nax_zoom.tick_params(axis=\"y\", labelleft=False)\nax_zoom.xaxis.set_major_formatter(FormatStrFormatter(\"%.2f\"))\nax_zoom.spines[\"top\"].set_visible(False)\nax_zoom.spines[\"right\"].set_visible(False)\nfor s in (\"left\", \"bottom\"):\n    ax_zoom.spines[s].set_color(INK_SOFT)\nax_zoom.yaxis.grid(True, alpha=0.15, linewidth=0.6, color=INK)\nax_zoom.set_title(\"Transit Detail\", fontsize=10, fontweight=\"medium\", pad=8, color=INK)\n\n# Figure title — \"lightcurve-transit · python · matplotlib · anyplot.ai\" is ~53 chars, fits at 12pt\nfig.suptitle(\n    \"lightcurve-transit · python · matplotlib · anyplot.ai\", fontsize=12, fontweight=\"medium\", y=0.98, color=INK\n)\n\nfig.subplots_adjust(left=0.09, right=0.97, top=0.91, bottom=0.12, wspace=0.15)\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}